字节流
- 抽象类
InputStream
和OutputStream
构成了字节输入/输出(I/O)类层次结构的基础。 - java中字节流处理的最基本单位为单个字节,通常用来处理二进制数据
- 以Stream结尾的是字节流
InputStream
int read(byte[] b)
int read(byte[] b,int off,int len)
//读入所有或某个范围内的字节,返回实际读入的字节数,或者在读到输入流结尾时返回-1.
byte[] readAllBytes()
//JDK9 产生一个字节数组,包含可以从当前流中读入的所有字节
long transferTo(OutputStream out)
//JDK9 将当前输入流中的所有字节传送到给定的输出流,返回传输的字节数。
int available()
//返回在不阻塞情况下可获取的字节数
void close()
//关闭这个输入流
OutputStream
void write(byte[] b)
void write(byte[] b,int off,int len)
//写出所有或某个范围内的字节到数组b中
void close()
//冲刷并关闭输出流
void flush()
//冲刷输出流
对象流
ObjectInputStream
和ObjectOutputStream
构成了对象流。可以把Java对象写入到数据源中,也能从数据源中把对象还原,可以进行对象的网络传输。- 使用
ObjectOutputStream
中的writeObject
方法保存对象 - 使用
ObjectInputStream
中的readObject
方法读入对象 - 存储读入的对象必须实现
Serializable
接口
在写出一个对象时,ObjectInputStream
会浏览对象的所有域,并存储它们的内容,但是,当一个对象被多个对象共享,待写出的对象中存在另一个对象的引用时,无法直接存储内容,也不可能去保存内存地址,因为当对象重新加载时占用的是与原来完全不同的地址。所以,使用了一种序列化的机制,每个对象都是用一个序列号保存的。
序列化
- 对遇到的每一个对象引用都关联一个序列号
- 对每一个对象,第一次遇到时,保存其对象数据到输出流中
- 如果这个对象之前保存过,写出一个“标记”
反序列化
- 对于对象输入流中的对象,,第一次遇到其序列号时,构建它并用流中的数据初始化
- 当遇到一个“标记”,获取与这个序列号相关联的引用
注意:
- 对于类中静态域和瞬时域的值都无法保存
- 使用
transient
关键字进行标识,在对象被序列化时会跳过,否则可能会引起本地方法崩溃
字符流
-
Java中的字符流处理的最基本的单元是Unicode码元(大小2字节),它通常用来处理文本数据。
-
对于Unicode文本,可以使用抽象类
Reader
和Writer
的子类,基本用法与InputStream
和OutputStream
类似 -
以Reader或者Writer结尾的是字符流
转换流
其是字符流和字节流之间的桥梁
InputStreamReader
InputStreamReader
将字节流转换为字符流。如果不指定字符集编码,该解码过程将使用平台默认的字符编码
OutputStreamWriter
OutputStreamWriter
将字符流转换为字节流。如果不指定字符集编码,该解码过程将使用平台默认的字符编码
文件读写
FileInputStream
/FileReader
和FileOutputStream
/FileWriter
可以提供附着在一个磁盘文件上的输入流和输出流,需要向其构造器提供一个文件路径:
- 绝对路径
- 相对路径:所有在
java.io
中的类的相对路径名是从工作目录开始,可以通过调用System.getProperty("user.dir")
来获得这个信息。
读取文本信息为防止乱码问题,最好使用字符流
读取图像,视频等非文本信息,最好使用字节流
FileInputStream(String name)
FileInputStream(File file)
//可以通过路径或一个File类构造
缓冲流
再读写数据时,让数据在缓冲区能减少系统实际对原始数据来源的存取次数,因为一次能做多个数据单位的操作,相较而言,对于从文件读取数据或将数据写入文件,比起缓冲区的读写要慢多了。所以使用缓冲区的流,一般都会比没有缓冲区的流效率更高,拥有缓冲区的流别称为缓冲流,包括BufferedInputStream
、BufferedOutputStream
类和BufferedReader
、BufferedWriter
类。缓冲流把数据从原始流成块读入或把数据积累到一个大数据块后再成批写出,通过减少通过资源的读写次数来加快程序的执行。缓冲流一般作为装饰器使用。
组合过滤器
某些输入流(例如FileInputStream
和由URL类的OpenStream
方法返回的输入流)可以从文件和其他外部的位置上获取字节,而其他的输入流(例如DataInputStream
)可以读取到数字文本信息。
为了方便使用可以对二者进行组合,例如,为了从文件中读取数字:
DataInputStream dis = new DataInputStream(new FileInputStream("xx.dat"));
double num = dis.readDouble();
类似的,可以通过不断嵌套过滤器来添加多重功能,例如,输入流在默认情况下是不被缓冲区缓存的,也就是说,每个对read
的调用都会请求操作系统再分发一个字节。相比之下,请求一个数据块并将其置于缓冲区中会显得更加高效。如果我们想使用缓冲机制读取文件数据,那么可以如下构造:
DataInputStream dis = new DataInputStream(
new BifferedInputStram(
new FileInputStream("xx.dat")));
try-with-resource
InputStream
、OutputStream
、Reader
和Writer
都实现了Closeable
接口。
Closeable
接口扩展了AutoCloseable
接口。因此对任何Closeable
进行操作时,都可以使用try-with-resource语句
带资源的try语句会在try块退出时,自动调用close()
方法。下面给出一个例子:
try(Scanner in = new Scanner(new FileInputStream("/user/share/dict/words")),"UTF-8"){
while(in.hasNext)
System.out.println(in.next);
}
这个块正常退出或者存在一个异常时,都会调用in.close()
方法,就好像使用了finally块一样。
还可以指定多个资源,用分号隔开就可以了。