java基础13:I/O

来源:互联网 发布:it课程体系 编辑:程序博客网 时间:2024/06/05 19:42

 一、概述

1、定义

在变量数组中和对象中存放的数据是暂时的,程序结束后就会丢失。为了能够永久的保存数据,需要将其存储在磁盘中。

java中的I/O技术可以将数据保存到本地,以达到永久保存的要求。

2、流

流是一组有序的序列,根据操作的类型,可分为输入流和输出流。


3、IO.体系

字节流的两个顶层父类:

1,InputStream  2,OutputStream.


字符流的两个顶层父类:

1,Reader 2,Writer


这些体系的子类都以父类名作为后缀。 

而且子类名的前缀就是该对象的功能。

如图:




 二、字符流

1、字符流的由来:

其实就是:字节流读取文字字节数据后,不直接操作而是先查指定的编码表。获取对应的文字。

在对这个文字进行操作。简单说:字节流+编码表 

2、FileReader与FileWriter

a、FileWirter写入文本

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:14px;">FileWriter fw = new FileWriter("d:\\jinfulin.txt");   
  2. w.write("dfs");  
  3. fw.close();</span>  

b、FileReader读取文本

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:14px;">FileReader fr = new FileReader("d:\\jinfulin.txt");  
  2. int num1 = fr.read();//读取第一个字符  
  3. int num2 = fr.read();//再次调用读取第二个字符(流特性嘛)  
  4.  System.out.println((char)num1);//打印,将数字转成字符  
  5.  System.out.println((char)num2);</span>  

c、字符缓冲区
[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:14px;">    FileReader fr = new FileReader("demo.txt");  
  2.         /* 
  3.          * 使用read(char[])读取文本文件数据。 
  4.          *   
  5.          * 先创建字符数组。 
  6.          */  
  7.         char[] buf = new char[1024];  
  8.   
  9.         int len = 0;  
  10.           
  11.         while((len=fr.read(buf))!=-1){//没有字符了读到数据位-1  
  12.             System.out.println(new String(buf,0,len));  
  13.         }  
  14. <span style="white-space:pre">        </span>fr.close();</span>  

d、如何将一些文字存储到硬盘一个文件中?

3、字符流缓冲区对象--BufferedReader与BufferedWriter

BfferedReader与BufferedWriter类就是把缓冲器封装成了对象,原理是一样的。
举例:文本从一个盘复制到另一个盘修改版



 三、字节流

字节流和字符流的基本操作是相同的,但字节流还可以操作其他媒体文件。

多说就是鄙视大家的智商了,举个例子来看看就好,

例:复制mp3
[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:14px;">    private static void myStreamCopy() throws IOException {  
  2.           
  3.         //定义输入输出流并加缓冲区  
  4.         BufferedOutputStream buffo = new BufferedOutputStream(new FileOutputStream("f:\\copy.mp3"));  
  5.         BufferedInputStream buffi = new BufferedInputStream(new FileInputStream("f:\\风吹麦浪.mp3"));  
  6.           
  7.         //开始复制  
  8.         int ch = 0;  
  9.         while((ch = buffi.read()) != -1)  
  10.         {  
  11.             buffo.write(ch);  
  12.         }  
  13.           
  14.         //关闭流  
  15.         buffo.close();  
  16.         buffi.close();  
  17.           
  18.     }</span>  


 四、转换流

1、 转换流的由来:

       a、字符流与字节流之间的桥梁
       b、方便了字符流与字节流之间的操作


2、转换流的应用:

      字节流中的数据都是字符时,转成字符流操作更高效。
InputStreamReader :字节到字符的桥梁。解码。
OutputStreamWriter:字符到字节的桥梁。编码。

3、举例:将控制台上的文字存储到文件中

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:14px;"><span style="white-space:pre">    </span>/* 
  2.      * 将控制台输入的文字存储到文件中。 
  3.      */  
  4.     public static void main(String[] args) throws IOException {  
  5.           
  6.         BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));  
  7.         BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("F:\\jinfulin.txt")));  
  8.           
  9.         String line =  null;  
  10.   
  11.         while((line = bufr.readLine()) != null)  
  12.         {  
  13.             if("over".equals(line))  
  14.                 break;  
  15.             bufw.write(line);  
  16.             System.out.println(line);  
  17.         }  
  18.           
  19.         bufr.close();  
  20.         bufw.close();  
  21.     }  
  22. </span>  



 

 五、流操作的基本规律

因为流对象太多,开发时不知道用哪个对象合适。弄清规律有助于我们使用。


1,明确源和目的

源:InputStream  Reader

目的:OutputStream  Writer

 

2,明确数据是否是纯文本数据。

源:是纯文本:Reader

---------否:InputStream

目的:是纯文本 Writer

------否:OutputStream

3,明确具体的设备。

源设备:

硬盘:File

键盘:System.in

内存:数组

网络:Socket流

目的设备:

硬盘:File

控制台:System.out

内存:数组

网络:Socket流

 

4,是否需要其他额外功能。

1,是否需要高效(缓冲区);

2,转换。



 六、File类

1、定义:

文件和目录路径名的抽象表现形式

2、特点:

        1)用来将文件或文件夹封装成对象
        2)方便于对文件与文件夹的属性信息进行操作
        3)File类的实例是不可变的;也就是说,一旦创建,File 对象表示的抽象路径名将永不改变
        4)File对象可以作为参数传递给流的构造函数

3、初始化:

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:14px;">//可以将一个已存在的,或者不存在的文件或者目录封装成file对象。  
  2.         File f1 = new File("c:\\a.txt");  
  3.           
  4.         File f2 = new File("c:\\","a.txt");  
  5.           
  6.         File f = new File("c:\\");  
  7.           
  8.         File f3 = new File(f,"a.txt");  
  9.   
  10.         File f4 = new File("c:"+File.separator+"abc"+File.separator+"a.txt");</span>  

4、 File对象的常见方法。


a、获取
[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:14px;"><span style="white-space:pre">        </span>File file = new File("a.txt");  
  2.           
  3.         String name = file.getName();//获取文件名(a.txt)  
  4.         String absPath = file.getAbsolutePath();//绝对路径。  
  5.         String path = file.getPath();//相对路径  
  6.         long len = file.length();//文件长度(大小)  
  7.         long time = file.lastModified();//最后修改时间</span>  

b、创建于删除
[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:14px;">File dir = new File("f:\\a1\\22\\jin.txt");  
  2.           
  3.         boolean b = dir.mkdir();//创建文件  
  4.         dir.mkdirs();//创建多级目录  
  5.         System.out.println(dir.delete());   
  6.         boolean b = file.createNewFile();//如果不存在就创建     </span>  
c、判断
[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:14px;">        boolean b = f.exists(); // 判断是否存在。   
  2.           
  3.         System.out.println(f.isFile());//是否是文件  
  4.         System.out.println(f.isDirectory());//是否是一个目录</span>  

d、重命名
[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:14px;"><span style="white-space:pre">        </span>File f1 = new File("c:\\kkk.mp3");  
  2.         File f2 = new File("d:\\ccc.mp3");    
  3.         boolean b = f1.renameTo(f2);      
  4.         System.out.println("ccc="+b);</span>  

5、 拓展应用

a、 获取当前目录下的文件以及文件夹的名称,包含隐藏文件。
[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:14px;">        String[] names = file.list();  
  2. <span style="white-space:pre">        </span>if(names == null)//如果为空就返回,避免出现空指针异常  
  3. <span style="white-space:pre">            </span>return;  
  4.         System.out.println(names.length);  
  5.           
  6.         for(String name : names){  
  7.             System.out.println(name);  
  8.         }</span>  


b、过滤所有以某某结尾的文件


c、深度历遍所有文件





d、删掉一个文件夹(从里往外删,递归)

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:14px;">public class DeleteAll {  
  2.   
  3.     public static void main(String[] args) {  
  4.         File dir = new File("f:\\1234");  
  5. //      dir.delete();//直接删是删不掉的  
  6.         dirdelete(dir);  
  7.     }  
  8.     private static void dirdelete(File dir) {  
  9.         File[] files = dir.listFiles();  
  10.         if (files == null)  
  11.             return;  
  12.           
  13.         for (File file : files) {  
  14.             if(file.isDirectory()){//如果是目录就递归  
  15.                 dirdelete(file);  
  16.             }  
  17.             //不是目录就删掉  
  18.             System.out.println(file.getAbsolutePath() + "----"+ file.delete());  
  19.         }  
  20.         //最后再删掉根目录的文件夹(此时已经空了)  
  21.         System.out.println(dir.getAbsolutePath() + "----"+ dir.delete());  
  22.     }  
  23.   
  24. }</span>  


 七、Properties类




1、概述

Properties类并不属于IO包中的类,而是属于map集合,在前面map集合章节也有提到,不过由于该集合中数据用到流,在这里说更合适。

2、特点:

  1,该集合中的键和值都是字符串类型。
  2,集合中的数据可以保存到流中,或者从流获取。 通常该集合用于操作以键值对形式存在的配置文件。  

3、举例

定义功能,获取一个应用程序运行的次数,如果超过5次,给出使用次数已到请注册的提示。并不要在运行程序。


[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. <span style="font-size:14px;">public static void getAppCount() throws IOException{  
  2.           
  3.         //将配置文件封装成File对象。  
  4.         File confile = new File("count.properties");  
  5.           
  6.         if(!confile.exists()){//健壮性判断  
  7.             confile.createNewFile();  
  8.         }  
  9.           
  10.         //集合中的数据来自于一个文件。   
  11.         //注意;必须要保证该文件中的数据是键值对。  
  12.         //需要使用到读取流。   
  13.         FileInputStream fis = new FileInputStream(confile);  
  14.         Properties prop = new Properties();  
  15.         prop.load(fis);//集合中加载一个文件输入流  
  16.           
  17.         //从集合中通过键获取次数。        
  18.         String value = prop.getProperty("time");  
  19.         //定义计数器。记录获取到的次数。  
  20.         int count =0;  
  21.         if(value!=null){  
  22.             count = Integer.parseInt(value);  
  23.             if(count>=5){  
  24.                 throw new RuntimeException("使用次数已到,请注册,给钱!");  
  25.             }  
  26.         }  
  27.         count++;  
  28.         //将改变后的次数重新存储到集合中。  
  29.         //将集合中数据存储到文件中,使用store方法。  
  30.         prop.setProperty("time", count+"");  
  31.         FileOutputStream fos = new FileOutputStream(confile);  
  32.         prop.store(fos, "注释.....");  
  33.         fos.close();  
  34.         fis.close();          
  35.     }</span>  

 

I

O也写作”I/O”,可理解为In和Out,即输入与输出,所以,IO体系的基本功能就是:读与写。

1.作用:读写设备上的数据,硬盘文件、内存、键盘、网络...

根据数据的走向,可分为:输入流、输出流

根据处理的数据类型,可分为:字节流、字符流

2.字节流与字符流

字节流可以处理所有类型的数据,如MP3、图片、文字、视频等。在读取时,读到一个字节就返回一个字节。在Java中对应的类都是”Stream”结尾。

字符流仅能够处理纯文本数据,如txt文本等。在读取时,读到一个或者多个字节,先查找指定的编码表,然后将查到的字符返回。在Java中对应的类都是”Reader”或者”Writer”结尾。

 

1.java.io包

Java.io包几乎包含了所有操作输入、输出需要的类。所有的这些流类代表了输入源和输出目标。

Java.io包流支持很多种格式,比如:基本类型、对象、本地化字符集等等。

一个流可以理解为一个数据的序列。输入流表示从一个源读取数据,输出流表示向一个目标写数据。

Java 为I/O提供了强大而灵活的支持,使其更广泛的应用到文件传输和网络编程中。

2.读取控制台输出

Java控制台输出由System.in完成。

为了获得一个绑定到控制台的字符流,你可以把System.in包装在一个BufferedReader 对象中来创建一个字符流。

下面是创建BufferedReader的基本语法:

BufferedReader br = new BufferedReader(new

                      InputStreamReader(System.in));

BufferedReader对象创建后,我们便可以使用read()方法从控制台读取一个字符,或者用readLine()方法读取一个字符串。

3.从控制台读取多字符输出

从BufferedReader对象读取一个字符要使用read()方法,它的语法如下:

int read( ) throws IOException

每次调用read()方法,它从输入流读取一个字符并把该字符作为整数值返回。 当流结束的时候返回-1。该方法抛出IOException。

 

3.从控制台读取字符串

从标准输入读取一个字符串需要使用BufferedReader的readLine()方法。

它的一般格式是:

String readLine( ) throws IOException

 

4.控制台输出

在此前已经介绍过,控制台的输出由 print( ) 和println( )完成。这些方法都由类PrintStream 定义,System.out是该类对象的一个引用。

PrintStream 继承了OutputStream类,并且实现了方法write()。这样,write()也可以用来往控制台写操作。

PrintStream 定义write()的最简单格式如下所示:

void write(int byteval)

该方法将byteval的低八位字节写到流中。

 

5.FileInputStream

该流用于从文件读取数据,它的对象可以用关键字new来创建。

有多种构造方法可用来创建对象。

可以使用字符串类型的文件名来创建一个输入流对象来读取文件:

InputStream f = new FileInputStream("C:/java/hello");

也可以使用一个文件对象来创建一个输入流对象来读取文件。我们首先得使用File()方法来创建一个文件对象:

File f = new File("C:/java/hello");

InputStream f = new FileInputStream(f);

创建了InputStream对象,就可以使用下面的方法来读取流或者进行其他的流操作。

 

序号

方法及描述

1

public void close() throws IOException{}
关闭此文件输入流并释放与此流有关的所有系统资源。抛出IOException异常。

2

protected void finalize()throws IOException {}
这个方法清除与该文件的连接。确保在不再引用文件输入流时调用其 close 方法。抛出IOException异常。

3

public int read(int r)throws IOException{}
这个方法从InputStream对象读取指定字节的数据。返回为整数值。返回下一字节数据,如果已经到结尾则返回-1。

4

public int read(byte[] r) throws IOException{}
这个方法从输入流读取r.length长度的字节。返回读取的字节数。如果是文件结尾则返回-1。

5

public int available() throws IOException{}
返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取的字节数。返回一个整数值。

 

6.FileOutputStream

该类用来创建一个文件并向文件中写数据。

如果该流在打开文件进行输出前,目标文件不存在,那么该流会创建该文件。

有两个构造方法可以用来创建FileOutputStream 对象。

使用字符串类型的文件名来创建一个输出流对象:

OutputStream f = new FileOutputStream("C:/java/hello")

也可以使用一个文件对象来创建一个输出流来写文件。我们首先得使用File()方法来创建一个文件对象:

File f = new File("C:/java/hello");

OutputStream f = new FileOutputStream(f);

创建OutputStream 对象完成后,就可以使用下面的方法来写入流或者进行其他的流操作。

 

序号

方法及描述

1

public void close() throws IOException{}
关闭此文件输入流并释放与此流有关的所有系统资源。抛出IOException异常。

2

protected void finalize()throws IOException {}
这个方法清除与该文件的连接。确保在不再引用文件输入流时调用其 close 方法。抛出IOException异常。

3

public void write(int w)throws IOException{}
这个方法把指定的字节写到输出流中。

 

public void write(byte[] w)

把指定数组中w.length长度的字节写到OutputStream中。

 

下面是一个演示InputStream和OutputStream用法的例子:

import java.io.*;

 

public class fileStreamTest{

 

   public static void main(String args[]){

  

   try{

      byte bWrite [] = {11,21,3,40,5};

      OutputStream os = new FileOutputStream("test.txt");

      for(int x=0; x < bWrite.length ; x++){

         os.write( bWrite[x] ); // writes the bytes

      }

      os.close();

    

      InputStream is = new FileInputStream("test.txt");

      int size = is.available();

 

      for(int i=0; i< size; i++){

         System.out.print((char)is.read() + "  ");

      }

      is.close();

   }catch(IOException e){

      System.out.print("Exception");

   }   

   }

}

上面的程序首先创建文件test.txt,并把给定的数字以二进制形式写进该文件,同时输出到控制台上。

以上代码由于是二进制写入,可能存在乱码,你可以使用以下代码实例来解决乱码问题:

//文件名 :fileStreamTest2.java

import java.io.*;

 

public class fileStreamTest2{

        public static void main(String[] args) throws IOException {

              

               File f = new File("a.txt");

               FileOutputStream fop = new FileOutputStream(f);

               // 构建FileOutputStream对象,文件不存在会自动新建

              

               OutputStreamWriter writer = new OutputStreamWriter(fop, "UTF-8");

               // 构建OutputStreamWriter对象,参数可以指定编码,默认为操作系统默认编码,windows上是gbk

              

               writer.append("中文输入");

               // 写入到缓冲区

              

               writer.append("\r\n");

               //换行

              

               writer.append("English");

               // 刷新缓存冲,写入到文件,如果下面已经没有写入的内容了,直接close也会写入

              

               writer.close();

               //关闭写入流,同时会把缓冲区内容写入文件,所以上面的注释掉

              

               fop.close();

               // 关闭输出流,释放系统资源

 

               FileInputStream fip = new FileInputStream(f);

               // 构建FileInputStream对象

              

               InputStreamReader reader = new InputStreamReader(fip, "UTF-8");

               // 构建InputStreamReader对象,编码与写入相同

 

               StringBuffer sb = new StringBuffer();

               while (reader.ready()) {

                       sb.append((char) reader.read());

                       // 转成char加到StringBuffer对象中

               }

               System.out.println(sb.toString());

               reader.close();

               // 关闭读取流

              

               fip.close();

               // 关闭输入流,释放系统资源

 

        }

}

 

 7.Java中目录

 

1)创建目录

File类中有两个方法可以用来创建文件夹:

  • mkdir( )方法创建一个文件夹,成功则返回true,失败则返回false。失败表明File对象指定的路径已经存在,或者由于整个路径还不存在,该文件夹不能被创建。
  • mkdirs()方法创建一个文件夹和它的所有父文件夹。

下面的例子创建 "/tmp/user/java/bin"文件夹:

import java.io.File;

 

public class CreateDir {

   public static void main(String args[]) {

      String dirname = "/tmp/user/java/bin";

      File d = new File(dirname);

      // 现在创建目录

      d.mkdirs();

  }

}

编译并执行上面代码来创建目录"/tmp/user/java/bin"。

注意:Java在UNIX和Windows自动按约定分辨文件路径分隔符。如果你在Windows版本的Java中使用分隔符(/) ,路径依然能够被正确解析。

 

2)读取目录

 

一个目录其实就是一个File对象,它包含其他文件和文件夹。

如果创建一个File对象并且它是一个目录,那么调用isDirectory( )方法会返回true。

可以通过调用该对象上的list()方法,来提取它包含的文件和文件夹的列表。

下面展示的例子说明如何使用list()方法来检查一个文件夹中包含的内容:

import java.io.File;

 

public class DirList {

   public static void main(String args[]) {

      String dirname = "/tmp";

      File f1 = new File(dirname);

      if (f1.isDirectory()) {

         System.out.println( "Directory of " + dirname);

         String s[] = f1.list();

         for (int i=0; i < s.length; i++) {

            File f = new File(dirname + "/" + s[i]);

            if (f.isDirectory()) {

               System.out.println(s[i] + " is a directory");

            } else {

               System.out.println(s[i] + " is a file");

            }

         }

      } else {

         System.out.println(dirname + " is not a directory");

    }

  }

}

 

8.File类的使用 

 

 

 

 

 


I/O包中的其他类

 一、对象流(ObjectInputStream/ObjectOutputStream)

1、概述

将堆内存中的对象存入硬盘,保留对象中的数据,称之为对象的持久化(或序列化)。使用到的两个类:ObjectInputStream和ObjectOutputStream

被操作对象需要实现Serializable

 2、特点

对象的序列化和反序列化。-----------writeObject  readObject

Serializable标记接口--------------------用于给被序列化的类家里ID号

关键字:transient------------------------短暂的,static和transient的对象都不写入

 transient:非静态数据不想被序列化可以使用这个关键字修饰。 

 

3、举例: 

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. public static void readObj() throws IOException, ClassNotFoundException {  
  2.         ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.object"));  
  3.         //对象的反序列化。   
  4.         Person p = (Person)ois.readObject();      
  5.         System.out.println(p.getName()+":"+p.getAge());   
  6.         ois.close();      
  7.     }  
  8.   
  9.     public static void writeObj() throws IOException, IOException {  
  10.         ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.object"));  
  11.         //对象序列化。  被序列化的对象必须实现Serializable接口。   
  12.         oos.writeObject(new Person("小强",30));  
  13.         oos.close();  
  14.     }  

 二、RandomAccessFile随机访问文件:

一、概述

        RandomAccessFile此类的实例支持对随机访问文件的读取和写入,自身具备读写方法。


2、特点:

**既可读取,又可以写入。

**内部维护了一个大型的byte数组,通过对数组的操作完成读取和写入。

**通过getFilePointer方法获取指针的位置,还可以通过seek方法设置指针的位置。

**该对象的内容应该封装了字节输入流和字节输出流。

**该对象只能操作文件。

通过seek方法操作指针,可以从这个数组中的任意位置上进行读和写

可以完成对数据的修改。

但是要注意:数据必须有规律。




3、举例:

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1.         //定义一个随机访问文件,可读可写  
  2.         RandomAccessFile raf = new RandomAccessFile("ranacc.txt","rw");  
  3.         raf.write("张三".getBytes());//写入内容  
  4.         raf.writeInt(97);  
  5.   
  6. <span style="white-space:pre">        </span>//通过seek设置指针的位置。  
  7. <span style="white-space:pre">        </span>RandomAccessFile raf = new RandomAccessFile("ranacc.txt", "r");  
  8.         raf.seek(1*8);//随机的读取。只要指定指针的位置即可。   
  9.         byte[] buf = new byte[4];  
  10.         raf.read(buf);  


 

 三、管道流:

1、概述

管道流包括PipedOutputStream和PipedInputStream ,且需要和多线程技术相结合,不知道多线程的知识大家是否还记得。看例子来回忆。

2、举例


 四、DataInputStream与ByteArrayInputStream

1、用操作基本数据类型值的对象。

DataInputStream

DataOutputStream

这两个读写对象,可用于操作基本数据类型的流对象,包含读写各种基本数据类型的方法。


2、设备是内存的流对象。

ByteArrayInputStream ByteArrayOutputStream

CharArrayReader  CharArrayWriter

a、这个对象并没有调用底层资源,所以不用关闭流资源,即使关闭后,仍可调用。 

b、内部包含缓冲区,相当于以内存作为流操作源和目的,不会产生任何IO异常。 

c、将一个数字写入另一个数组(都是在内存中操作的)


0 0
原创粉丝点击