虽然看了一些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 :当缓冲流输出数据时候,系统先从缓冲区读出数据,待缓冲区为空时,系统再从内存读取数据到缓冲区。
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?????
BufferedInputStream
和BufferedOutputStream
类就是实现了缓冲功能的输入流/输出流。使用带缓冲的输入输出流,效率更高,速度更快
从构造方法中我们可以知道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
来源:oschina
链接:https://my.oschina.net/u/4382176/blog/4151241