一、什么是IO
Input/Output即输入&输出,指数据从一个地方传输另一个地方的过程,对于计算机来讲文件的拷贝、编写、保存都是IO的过程
Java针对IO操作提供了相应的API,Java中几乎所有的IO操作都需要使用java.io包
二、IO分类
按流向分:
输入流(input):读数据。
输出流(ouput):写数据。
按流的处理类型分:
字节流(byte):处理任何类型的数据,包括二进制数据,处理单元为1个字节。
字符流(char):处理字符或者字符串数据,处理的单元为2个字节的Unicode字符,也就是要进行字符集的转化。
按流的功能分:
节点流:是底层流/低级流,直接跟数据源相接
处理流:包装节点流,即可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出。主要以增加缓冲的方式来提高输入输出的效率,提供了一系列的便捷方法,来一次输入输出大批量的数据,使用更加灵活方便。
三、JAVA-IO类
字节流
字节输入流:
抽象类:InputStream
实现类:
-
FileInputStream:用于从文件系统的文件中读取字节
-
FilterInputStream:包含一些其他的输入流,并将其作为基本的数据源,提供数据转换和其他功能
子类:
-
BufferedInputStream:字节缓冲输入流,,由于基础输入流一个字节一个字节读取,频繁与磁盘进行交互,造成读取速度较低.缓冲流的存在就是先将数据读取到缓冲流(内存中),然后一次性从内存中读取多个字符.提高读取的效率
-
DataInputStream:数据输入流,以机器无关的方式读取Java的基本类型
- PushbakInputStream:回退输入流,java中读取数据的方式是顺序读取,如果某个数据不需要读取,需要程序处理.PushBackInputStream就可以将某些不需要的数据回退到缓冲中
-
-
ObjectInputStream:将对象的原始数据序列化的输入流
-
PipedInputStream:管道输入流提供写入管道输出流的任何数据字节,实现管道化的概念
-
SequenceInputStream:将两个或者多个InputStream 转换成单一 InputStream
-
ByteArrayInputStream:字节数组输入流,在内存中创建一个字节数组缓冲区,从输入流读取的数据保存在该字节数组缓冲区中
字节输出流:
抽象类:OutputStream
实现类:
-
FileOutputStream:用于在文件系统的文件中写入字节
-
FilterOutputStream:包含一些其他的输出流,并将其作为基本的数据源,提供数据转换和其他功能
子类:
-
BufferedOutputStream:字节缓冲输出流
-
DataOutputStream:数据输出流
-
PrintStream:打印输出流,用来装饰其他输出流,为其他输出流添加功能,方便的打印各种数据值
-
-
ObjectOutputStream:对象输出流,它和ObjectInputStream一起对基本数据或者对象的持久存储。
-
PipedOutputStream:管道输出流,和PipedInputStream一起使用,能实现多线程间的管道通信
-
ByteArrayOutputStream:字节数组输出流,在内存中创建一个字节数组缓冲区,所有发送到输出流的数据保存在该字节数组缓冲区中
字符流
字符输入流:
抽象类:Reader
实现类:
-
BufferedReader:字符缓冲输入流
-
InputStreamReader:字符输入流
-
FileReader:按字符读取流中数据
-
PushbackReader:字符流阅读器,允许将字符推回到流中。
-
-
-
StringReader:将String字符串操作适配成 Reader字符操作
-
PipedReader:字符管道输入流
-
CharArrayReader:字符数组输入流,在内存中创建一个字符数组缓冲区,从输入流读取的数据保存在该字符数组缓冲区中
字符输出流:
抽象类:Writer
实现类:
-
BufferedWriter:字符缓冲输出流
-
OutputStreamWriter:字符输出流
-
FileWriter:按字符向流中写入数据
-
-
PrintWriter:将对象的格式化表示打印到文本输出流
-
StringWriter:写入到一个String中去,所以它内部提供了一个StringBuffer中用来保存数据
-
PipedWriter:字符管道输出流
-
CharArrayWriter:字符数组输出流,在内存中创建一个字符数组缓冲区,所有发送到输出流的数据保存在该字符数组缓冲区中
处理流
缓存流
-
BufferedInputStream:字节缓冲输入流
-
BufferedOutputStream:字节缓冲输出流
-
ByteArrayInputStream:字节数组缓冲输入流
-
ByteArrayOutputStream:字节数组缓冲输出流
-
BufferedReader:字符缓冲输入流
-
BufferedWriter:字符缓冲输出流
-
CharArrayReader:字符数组缓冲输入流
-
CharArrayWriter:字符数组缓冲输出流
转换流
-
InputStreamReader:用于将字节输入流转换为字符输入流(字节->字符)
-
OutputStreamWriter:用于将字符输出流转换为字节输出流(字符->字节)
打印流
-
PrintStream:字节打印流
-
PrintWriter:字符打印流
序列化和反序列化
序列化是将Java对象以一连串的字节保存在磁盘文件中的过程。
反序列化是将保存在磁盘中的java字节码重新转换成java对象称为反序列化
-
ObjectOutputStream:对象输出流,它的writeObject(Object obj)方法可以对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中
-
ObjectInputStream:对象输入流,它的readObject()方法源输入流中读取字节序列,再把它们反序列化成为一个对象,并将其返回
注意:只有实现了Serializable或Externalizable接口的类的对象才能被序列化,否则抛出异常!
public static void main(String[] args) throws IOException, ClassNotFoundException {
//被序列化的对象
Person p1 = new Person();
//反序列化的对象
Person p2;
//序列化
getSerial(p1);
//反序列化
p2 = backSerial();
}
//序列化
static void getSerial(Person p) throws IOException {
FileOutputStream fos = new FileOutputStream("obj.text");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(p);
oos.flush();
oos.close();
}
//反序列化
static Person backSerial() throws IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream("obj.text");
ObjectInputStream ois = new ObjectInputStream(fis);
Person p = (Person) ois.readObject();
return p;
}
常见问题
1、字节流与字符流的区别
字节流在操作的时候本身是不会用到缓冲区(内存)的,是与文件本身直接操作的,而字符流在操作的时候是使用到缓冲区的
字节流在操作文件时,即使不关闭资源(close方法),文件也能输出,但是如果字符流不使用close方法的话,则不会输出任何内容,说明字符流用的是缓冲区,并且可以使用flush方法强制进行刷新缓冲区,这时才能在不close的情况下输出内容
2、那开发中究竟用字节流好还是用字符流好呢?
在所有的硬盘上保存文件或进行传输的时候都是以字节的方法进行的,包括图片也是按字节完成,而字符是只有在内存中才会形成的,所以使用字节的操作是最多的。
3、InputStreamReader 和FileReader的区别
InputStreamReader是FileReader的父类,InputStreamReader 是用来读取原始字节流,可指定编码格式,而FileReader是读取字符流,使用系统默认的编码格式,当读取中文文件是易出现乱码问题。要区别也就在于构造函数。
推荐使用:
File file = new File (filename);
InputStreamReader input =new InputStreamReader(new FileInputStream(file),"UTF-8");
BufferedReader br = new BufferedReader(input);