Java IO流

依然范特西╮ 提交于 2021-02-12 18:52:00

虽然看了一些code,但是对于Java IO流一直没有系统学习,今天在此做一个总结。

将数据冲外存中读取到内存中的称为输入流,将数据从内存写入外存中的称为输出流。

 

在整个Java.io包中最重要的就是5个类和一个接口。5个类指的是File、OutputStream、InputStream、Writer、Reader;一个接口指的是Serializable.掌握了这些IO的核心操作那么对于Java中的IO体系也就有了一个初步的认识了

  主要的类如下:

     1. File(文件特征与管理):用于文件或者目录的描述信息,例如生成新目录,修改文件名,删除文件,判断文件所在路径等。

     2. InputStream(二进制格式操作):抽象类,基于字节的输入操作,是所有输入流的父类。定义了所有输入流都具有的共同特征。

     3. OutputStream(二进制格式操作):抽象类。基于字节的输出操作。是所有输出流的父类。定义了所有输出流都具有的共同特征。

     Java中字符是采用Unicode标准,一个字符是16位,即一个字符使用两个字节来表示。为此,JAVA中引入了处理字符的流。

     4. Reader(文件格式操作):抽象类,基于字符的输入操作。

     5. Writer(文件格式操作):抽象类,基于字符的输出操作。

java.io包中包含了流式I/O所需要的所有类。在java.io包中有四个基本类:InputStream、OutputStream及Reader、Writer类,它们分别处理字节流和字符流:

 

基本数据流的I/O

输入/输出

字节流

字符流

输入流

Inputstream

Reader

输出流

OutputStream

Writer

 

1. 字节流InputStream/OutputStream

1. InputStream抽象类

      InputStream 为字节输入流,它本身为一个抽象类,必须依靠其子类实现各种功能,此抽象类是表示字节输入流的所有类的超类。 继承自InputStream  的流都是向程序中输入数据的,且数据单位为字节(8bit);

  (1) public abstract int read( ):读取一个byte的数据,返回值是高位补0的int类型值。若返回值=-1说明没有读取到任何字节读取工作结束。
  (2) public int read(byte b[ ]):读取b.length个字节的数据放到b数组中。返回值是读取的字节数。该方法实际上是调用下一个方法实现的
  (3) public int read(byte b[ ], int off, int len):从输入流中最多读取len个字节的数据,存放到偏移量为off的b数组中。

 1)FileInputStream 把一个文件作为一个InputStream,实现对文件的读取操作

2)ByteArrayInputStream:把内存中的一个缓冲区作为一个InputStream.

3)StringBufferInputStream把一个String对象作为一个InputStream.

2.OutputStream抽象类

输出流OutputStream类是字节输入流的抽象类,此抽象类表示输出字节流的所有类的超类。

1)FileOutputStream把一个文件作为一个OutputStream,实现对文件写操作

2)ByteArrayOutputStream把信息存入内存中的一个缓存区。

 1. public void write(byte b[ ]):将参数b中的字节写到输出流。
 2. public void write(byte b[ ], int off, int len) :将参数b的从偏移量off开始的len个字节写到输出流。

 4. public void flush( ) : 将数据缓冲区中数据全部输出,并清空缓冲区。
 5. public void close( ) : 关闭输出流并释放与流相关的系统资源。

3. 文件输入流: FileInputStream类

FileInputStream可以使用read()方法一次读入一个字节,并以int类型返回,或者是使用read()方法时读入至一个byte数组,byte数组的元素有多少个,就读入多少个字节。在将整个文件读取完成或写入完毕的过程中,这么一个byte数组通常被当作缓冲区,因为这么一个byte数组通常扮演承接数据的中间角色。

作用:以文件作为数据输入源的数据流。或者说是打开文件,从文件读数据到内存的类。

使用方法(1)       File fin=new File("d:/abc.txt");   FileInputStream in=new FileInputStream( fin);

使用方法(2)   FileInputStream  in=new  FileInputStream(“d: /abc.txt”);  //传这个参数进去还是会重新new一个file

 

4.文件输出流:FileOutputStream类

 

  作用:用来处理以文件作为数据输出目的数据流;或者说是从内存区读数据入文件

 

  方式1:
   File   f=new  File (“d:/myjava/write.txt ");
        FileOutputStream  out= new FileOutputStream (f);
  方式2:
  FileOutputStream out=new FileOutputStream(“d:/myjava/write.txt ");

举一个例子,将file1.txt的内容读出来存到file2.txt中。

 

 1 package lesson1212;
 2 
 3 import java.io.File;
 4 import java.io.FileInputStream;
 5 import java.io.FileNotFoundException;
 6 import java.io.FileOutputStream;
 7 import java.io.IOException;
 8 
 9 public class FileInputStreamTest {
10 
11     public static void main(String[] args) throws IOException {
12         File file = new File("C:/Workspace/file1.txt");
13         try {
14             FileInputStream fis = new FileInputStream(file);
15             FileOutputStream fos = new FileOutputStream("C:/Workspace/file2.txt");
16             //byte [] bytes = new byte[50];
17             //调用read(byte b[], int off, int len)其实这个地方是有问题的,取决于定义bytes数组长度,
18             //bytes被反复覆盖重写,最后可能会把一些多余的信息存到file2.txt中。 
19     /*        while(fis.read(bytes, 0, bytes.length) != -1){
20                 
21                 fos.write(bytes, 0, bytes.length);
22             }*/
23             int num;
24             while((num = fis.read())!=-1){   //这种才是正解
25                 fos.write(num);
26             }
27             fis.close();
28             fos.close();
29         } catch (FileNotFoundException e) {
30             // TODO Auto-generated catch block
31             e.printStackTrace();
32         }
33     }
34 }

 上面code中说的有个问题,其实多定义个size就可以:

            /*int size;
            //调用read(byte b[], int off, int len)其实这个地方是有问题的,取决于定义bytes数组长度,
            //bytes被反复覆盖重写,最后可能会把一些多余的信息存到file2.txt中。
            while((size = bis.read(bytes, 0, bytes.length)) != -1){                   
                bos.write(bytes, 0, size);               
            }*/

5. 缓冲输入输出流 BufferedInputStream/ BufferedOutputStream

理解紫色箭头部分,是一个缓冲流。

 计算机访问外部设备非常耗时。访问外存的频率越高,造成CPU闲置的概率就越大。为了减少访问外存的次数,应该在一次对外设的访问中,读写更多的数据。为此,除了程序和流节点间交换数据必需的读写机制外,还应该增加缓冲机制。缓冲流就是每一个数据流分配一个缓冲区,一个缓冲区就是一个临时存储数据的内存。这样可以减少访问硬盘的次数,提高传输效率。

 BufferedInputStream:当向缓冲流写入数据时候,数据先写到缓冲区,待缓冲区写满后,系统一次性将数据发送给内存。

 BufferedOutputStream :当缓冲流输出数据时候,系统先从缓冲区读出数据,待缓冲区为空时,系统再从内存读取数据到缓冲区。

 

* A:缓冲思想

 

  * 字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,

 

  * 这是加入了数组这样的缓冲区效果,java本身在设计的时候,

 

  * 也考虑到了这样的设计思想,所以提供了字节缓冲区流

 

* B.BufferedInputStream

 

  * BufferedInputStream内置了一个缓冲区(数组)

 

  * 从BufferedInputStream中读取一个字节时

 

  * BufferedInputStream会一次性从文件中读取8192个, 存在缓冲区中, 返回给程序一个

 

  * 程序再次读取时, 就不用找文件了, 直接从缓冲区中获取

 

  * 直到缓冲区中所有的都被使用过, 才重新从文件中读取8192个

 

* C.BufferedOutputStream

 

  * BufferedOutputStream也内置了一个缓冲区(数组)

 

  * 程序向流中写出字节时, 不会直接写到文件, 先写到缓冲区中

 

  * 直到缓冲区写满, BufferedOutputStream才会把缓冲区中的数据一次性写到文件里

 1)将文件读入内存:

BufferedInputStream与FileInputStream相接

  FileInputStream in=new  FileInputStream( “file1.txt ” );

  BufferedInputStream bin=new  BufferedInputStream( in);

 

BufferedInputStream(InputStream in) //使用默认buf大小、底层字节输入流构建bis ,默认buffersize是8192
BufferedInputStream(InputStream in, int size) //使用指定buf大小、底层字节输入流构建bis 

 

2)将内存写入文件:

BufferedOutputStream与 FileOutputStream相接

FileOutputStreamout=new FileOutputStream(“file1.txt”);

BufferedOutputStream  bin=new BufferedInputStream(out);

BufferedOutputStream(OutputStream out); //使用默认大小、底层字节输出流构造bos。默认缓冲大小是 8192 字节( 8KB )

BufferedOutputStream(OutputStream out, int size); //使用指定大小、底层字节输出流构造bos  
将上面的例子加入缓冲流:

 1 package lesson1212;
 2 
 3 import java.io.BufferedInputStream;
 4 import java.io.BufferedOutputStream;
 5 import java.io.File;
 6 import java.io.FileInputStream;
 7 import java.io.FileNotFoundException;
 8 import java.io.FileOutputStream;
 9 import java.io.IOException;
10 
11 public class FileInputStreamTest {
12 
13     public static void main(String[] args) throws IOException {
14         File file = new File("C:/Workspace/file1.txt");
15         try {
16             FileInputStream fis = new FileInputStream(file);
17             BufferedInputStream bis = new BufferedInputStream(fis);
18             FileOutputStream fos = new FileOutputStream("C:/Workspace/file2.txt");
19             BufferedOutputStream bos = new BufferedOutputStream(fos);
20             
21             //byte [] bytes = new byte[50];
22             //调用read(byte b[], int off, int len)其实这个地方是有问题的,取决于定义bytes数组长度,
23             //bytes被反复覆盖重写,最后可能会把一些多余的信息存到file2.txt中。 
24     /*        while(bis.read(bytes, 0, bytes.length) != -1){
25                 
26                 bos.write(bytes, 0, bytes.length);
27             }*/
28             int num;
29             while((num = bis.read())!=-1){   //这种才是正解
30                 bos.write(num);
31             }
32             bis.close();
33             bos.close();
34         } catch (FileNotFoundException e) {
35             // TODO Auto-generated catch block
36             e.printStackTrace();
37         }
38     }
39 }

 这个地方有个疑问:什么时候需要加入BufferedInputStream和BufferedOutputStream?????

BufferedInputStreamBufferedOutputStream类就是实现了缓冲功能的输入流/输出流。使用带缓冲的输入输出流,效率更高,速度更快

从构造方法中我们可以知道BufferedInputStream没有无参构造方法,它必须传入一个InputStream(一般是FileInputStream),来一起使用,以提高读写效率。

那么什么时候flush()才有效呢?
答案是:当OutputStream是BufferedOutputStream时。

 

6. ByteArrayInputStream/ByteArrayOutputStream

  输出不一定非要输出到文件中,也可以输出到内存中,如:ByteArrayOutputStream。输入流的read方法是从流里面读出来数据,

    输出流的write方法时将内存中的数据写入到流中,方便输出出去。

ByteArrayInputStream 可以将字节数组转化为输入流 。
ByteArrayOutputStream可以捕获内存缓冲区的数据,转换成字节数组。

ByteArrayOutputStream 其中封装了一个byte类型的数组buf作为数据的缓存区,当进行数据写人的时候,数据会不断地写入buf缓存区中,该缓存区默认大小为32字节。每一次写人数据后,都要执行ensureCapacity方法来确定缓存区容量十分能够容纳写入数据,如果不够的时候会执行grow方法,将容量翻倍以适应写入的数据。当写入完成后,我们可以通过toByteArray方法,来获得缓存区数组的一个副本。因为这个特性,我们可以使用ByteArrayOutputStream进行一次性的数据写入。

7. 对象操作流(ObjectInputStream,ObjectOutputStream )

ObjectInputStream 称为 反序列化流,利用输入流从文件中读取对象;    ObjectOutputStream 称为 序列化流,利用输出流向文件中写入对象

特点:用于操作对象。可以将对象写入到文件中,也可以从文件中读取对象。主要用于序列化和反序列化。

添加一个例子:

 

  1 package lesson1212;
  2 
  3 import java.io.BufferedInputStream;
  4 import java.io.BufferedOutputStream;
  5 import java.io.ByteArrayInputStream;
  6 import java.io.ByteArrayOutputStream;
  7 import java.io.FileNotFoundException;
  8 import java.io.IOException;
  9 import java.io.ObjectInputStream;
 10 import java.io.ObjectOutputStream;
 11 import java.io.Serializable;
 12 
 13 public class ObjectInputStreamDemo {
 14 
 15     public static void main(String[] args) throws ClassNotFoundException {
 16 
 17         Person person1 = new Person("zhangsan",30);
 18         Person person2 = new Person("lisi",40);
 19         
 20         try {
 21             /*用FileInputStream作为输入流来操作
 22             ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:/Workspace/object.txt"));
 23             oos.writeObject(person1);
 24             oos.writeObject(person2);            
 25             ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:/Workspace/object.txt"));*/
 26             
 27             //用ByteArrayInputStream作为输入流来操作
 28             ByteArrayOutputStream bo = new ByteArrayOutputStream();
 29             ObjectOutputStream oos = new ObjectOutputStream(bo);
 30             oos.writeObject(person1);
 31             oos.writeObject(person2);            
 32             ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bo.toByteArray()));
 33             
 34             //下面这个地方运行报异常
 35             /*ByteArrayOutputStream bao = new ByteArrayOutputStream();
 36             BufferedOutputStream bo = new BufferedOutputStream(bao);
 37             ObjectOutputStream oos = new ObjectOutputStream(bo);
 38             oos.writeObject(person1);
 39             oos.writeObject(person2);            
 40             ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new ByteArrayInputStream(bao.toByteArray())));
 41             */        
 42             Person person1clone = (Person)ois.readObject();
 43             Person person2clone = (Person)ois.readObject();            
 44             System.out.println(person1clone);
 45             System.out.println(person2clone);            
 46             
 47             oos.close();
 48             ois.close();
 49         } catch (FileNotFoundException e) {
 50             // TODO Auto-generated catch block
 51             e.printStackTrace();
 52         } catch (IOException e) {
 53             // TODO Auto-generated catch block
 54             e.printStackTrace();
 55         }
 56         
 57     }
 58 
 59 }
 60 
 61 class Person implements Serializable{
 62     
 63     /**
 64      * 
 65      */
 66     private static final long serialVersionUID = 1L;
 67     private String name;
 68     private int age;
 69     
 70     public Person(String name, int age) {
 71         this.name = name;
 72         this.age = age;
 73     }
 74     /**
 75      * @return the name
 76      */
 77     public String getName() {
 78         return name;
 79     }
 80     /**
 81      * @param name the name to set
 82      */
 83     public void setName(String name) {
 84         this.name = name;
 85     }
 86     /**
 87      * @return the age
 88      */
 89     public int getAge() {
 90         return age;
 91     }
 92     /**
 93      * @param age the age to set
 94      */
 95     public void setAge(int age) {
 96         this.age = age;
 97     }
 98     /* (non-Javadoc)
 99      * @see java.lang.Object#toString()
100      */
101     @Override
102     public String toString() {
103         return "Person  name " + this.name + ", age " + this.age;
104     }
105     
106     
107 }

 

 注意:

1:ByteArrayInputStream, FileInputStream ,StringBufferInputStream是三种基本的介质流,分别从Byte数组,文件,StringBuffer中读取数据。

2:ObjectInputStream和BufferedInputStream都是装饰流。  例如BufferedInputStream使其他流具有缓冲功能。

3:ByteArrayOutputStream, FileOutputStream, 是两种基本的介质流,分别向Byte数组,文件中写入数据。

4:ObjectOutputStream和BufferedOutputStream都是装饰流。

在上面第7小节,code里面想多用一次BufferedInputStream,可是有错误,下面code解决了。不过一般应该是不会这样做的。

  1 package lesson1212;
  2 
  3 import java.io.BufferedInputStream;
  4 import java.io.BufferedOutputStream;
  5 import java.io.ByteArrayInputStream;
  6 import java.io.ByteArrayOutputStream;
  7 import java.io.FileInputStream;
  8 import java.io.FileNotFoundException;
  9 import java.io.FileOutputStream;
 10 import java.io.IOException;
 11 import java.io.ObjectInputStream;
 12 import java.io.ObjectOutputStream;
 13 import java.io.Serializable;
 14 
 15 public class ObjectInputStreamDemo {
 16 
 17     public static void main(String[] args) throws ClassNotFoundException {
 18 
 19         Person person1 = new Person("zhangsan",30);
 20         Person person2 = new Person("lisi",40);
 21         
 22         try {
 23             /*用FileInputStream作为输入流来操作
 24             ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:/Workspace/object.txt"));
 25             oos.writeObject(person1);
 26             oos.writeObject(person2);            
 27             ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:/Workspace/object.txt"));*/
 28             
 29             //用ByteArrayInputStream作为输入流来操作
 30 /*            ByteArrayOutputStream bos = new ByteArrayOutputStream();
 31             ObjectOutputStream oos = new ObjectOutputStream(bos);            
 32             oos.writeObject(person1);
 33             oos.writeObject(person2);    
 34             ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
 35             ObjectInputStream ois = new ObjectInputStream(bis);*/
 36             
 37             //下面这个地方运行报异常
 38             //FileOutputStream fos = new FileOutputStream("C:/Workspace/object.txt");//对应line46
 39             ByteArrayOutputStream bao = new ByteArrayOutputStream();                        
 40             BufferedOutputStream bos = new BufferedOutputStream(bao);
 41             ObjectOutputStream oos = new ObjectOutputStream(bos);
 42             oos.writeObject(person1);
 43             oos.writeObject(person2);
 44             bos.flush();
 45         
 46             //FileInputStream fis = new FileInputStream("C:/Workspace/object.txt");  //对应于line38
 47             ByteArrayInputStream bais = new ByteArrayInputStream(bao.toByteArray());
 48             BufferedInputStream bis = new BufferedInputStream(bais);
 49             ObjectInputStream ois = new ObjectInputStream(bis);
 50             
 51             Person person1clone = (Person)ois.readObject();
 52             Person person2clone = (Person)ois.readObject();            
 53             System.out.println(person1clone);
 54             System.out.println(person2clone);            
 55             
 56             oos.close();
 57             ois.close();
 58         } catch (FileNotFoundException e) {
 59             // TODO Auto-generated catch block
 60             e.printStackTrace();
 61         } catch (IOException e) {
 62             // TODO Auto-generated catch block
 63             e.printStackTrace();
 64         }
 65         
 66     }
 67 
 68 }
 69 
 70 class Person implements Serializable{
 71     
 72     /**
 73      * 
 74      */
 75     private static final long serialVersionUID = 1L;
 76     private String name;
 77     private int age;
 78     
 79     public Person(String name, int age) {
 80         this.name = name;
 81         this.age = age;
 82     }
 83     /**
 84      * @return the name
 85      */
 86     public String getName() {
 87         return name;
 88     }
 89     /**
 90      * @param name the name to set
 91      */
 92     public void setName(String name) {
 93         this.name = name;
 94     }
 95     /**
 96      * @return the age
 97      */
 98     public int getAge() {
 99         return age;
100     }
101     /**
102      * @param age the age to set
103      */
104     public void setAge(int age) {
105         this.age = age;
106     }
107     /* (non-Javadoc)
108      * @see java.lang.Object#toString()
109      */
110     @Override
111     public String toString() {
112         return "Person  name " + this.name + ", age " + this.age;
113     }
114     
115     
116 }

 可能没分清这几个Stream具体的使用场景。所以才出现上面那么怪的引用BufferedInputStream。希望哪位大侠指出这么用的不好。

对于字符流,没有研究,后面继续加上。还有一些其他知识加进去。

下面是参考的博客:

https://blog.csdn.net/moonfish0607/article/details/77161138

https://www.cnblogs.com/dolphin0520/p/3791327.html

https://www.cnblogs.com/Jtianlin/p/4188945.html

https://www.cnblogs.com/java1024/p/8906567.html

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!