输入输出流体系
处理流的用法
使用处理流来包装节点流,程序通过处理流来执行输入输出,让节点流与底层I/O设备、文件交互。如通过PrintStream
处理流来包装OutputStream
,使用处理流后的输出流更加方便。
输入输出流体系提供了近40个类,常用的类分成如下:
分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
---|---|---|---|---|
对象流 | ObjectInputStream |
ObjectOutputStream |
||
抽象基类 | FilterInputStream |
FilterOutputStream |
FilterReader |
FilterWriter |
抽象基类 | IuputStream |
OutputStream |
Reader |
Writer |
访问文件 | FileInputStream |
FileOutputStream |
FileReader |
FileWriter |
访问数组 | ByteArrayInputStream |
ByteArrayOutputStream |
CharArrayReader |
CharArrayWriter |
访问管道 | PipedInputStream |
PipedOutputStream |
PipedReader |
PipedWriter |
访问字符串 | StringReader |
StringWriter |
||
缓冲流 | BufferedInputStream |
BufferedOutputStream |
BufferedReader |
BufferedWriter |
通常字节流的功能更加强大,因为计算机的数据都是二进制的,而字节流可以处理所有二进制文件;如果要处理文本文件,则应该考虑使用字符流处理。另外还有一些不在java.io
包下的字节流,它们具有特殊的功能。表中有四个访问管道的IO流,它们用于实现进程间的通信。四个缓冲流增加了缓冲功能,提高输入输出效率,同时需要使用flush()
才能将缓冲区内容写入IO节点
。对象流用于实现对象的序列化。
转换流
有两个转换流用于实现字节流转换成字符流,其中InputStreamReader
将字节输入流转换成字符输入流,OutputStreamWriter
将字节输出流转换成字符输出流。Java使用System.in
代表标准输入,它是InputStream
类的实例,使用不是很方便,所以用InputStreamReader
将其转换成字符输入流;再者,普通的Reader
读取输入输入内容不方便,可以将Reader
包装成BufferedReader
,利用readLine()
方法一次读取一行内容。
1 | InputStreamReader reader = new InputStreamReader(System.in); |
推回输入流
在IO流体系中有两个流比较特殊,PushbackInputStream
和PushbackReader
,它们都提供如下三个方法:
voidunread(byte[]/char[] buf)
:将一个字节/字符数组内容推入缓冲区,从而能重复读取刚刚读取的内容。void unread(byte[]/char[] b,int off,int len)
:将一个字节/字符数组里从off开始,长度为len
字节/字符内容推入缓冲区,从而允许重复读取。void unread(int b)
:将一个字节/字符推入缓冲区,从而允许重复读取。
这三个方法与InputStream
和Reader
中的三个方法相对应,它们各有一个推回缓冲区,当调用unread()
方法时,系统会把指定数组内容推回缓冲区,并且每次调用read()
方法时总是从推回缓冲区读取。当完全读取缓冲区内容
后,但还没有装满read()
的存放数组时才会从输入流中读取。当创建PushbackInputStream
和PushbackReader
时需要指定缓冲区大小,而默认大小为1。如果超出大小将会引发IO异常。
重定向输入输出
Java的标准输入/输出分别通过System.in
和System.out
代表,获取输入和输出,输出是输出到屏幕上。在System
类下有如下三个重定向的方法:
static void setErr(PrintStream err)
:重定向标准错误输出流。static void setIn(InputStream in)
:重定向标准输入流。static void setOut(PrintStream out)
:重定向标准输出流。
1 | PrintStream p = new PrintStream(new FileOutputStream("out.txt")); |
以上代码重定向输出流到一个文本文件中,所以输出时将不会输出到屏幕上,而到了文件中。同样也可以重定向输入,指定从文件输入。
Java虚拟机读写进程数据
使用Runtime
对象的exec()
方法可以运行其他程序,该方法产生一个Process
对象,代表程序启动的子进程。Process
类提供了如下三个方法,用于让程序和其子进程进行通信。
InputStream getErrorStream()
:获取子进程的错误流。InputStream getInputStream()
:获取子进程的输入流。OutputStream getOutputStream()
:获取子进程的输出流。
需要注意的是,此处的输入输出流应该站在程序的角度上理解,让子进程读取程序中的数据,要用输出流而不是输出流,相当于子进程代替了文件节点一样。
RandomAccessFile
文件随机访问类
与普通的输入输出流不同,RandomAccessFile
支持随机任意访问,程序可以直接跳到文件任意地方来读写文件。它允许自由定位文件记录指针,RandomAccessFile
可以不从开始地方输出,所以可以在后面追加内容。同时,需要注意的是该类不能读写其他IO流节点,只能读写文件。每一个对象包含一个记录指针,用以标识当前读写处位置。
long getFilePointer()
:返回文件记录指针的位置。void seek(long pos)
:将文件记录指针定位到pos
位置。
RandomAccessFile
包含类似于InputStream
的三个read()
方法,用法和其他read()
方法完全一样,同样也包含类似的write()
方法。该类有两个构造器,只是形参不同,一个是使用String
参数指定文件名,另一个是使用File
参数指定文件名。此外,还需要指定一个mode
访问模式参数。
r
:只读打开文件。rw
:读写方式打开文件,若不存在则创建文件。rws
:读写方式打开,文件和元数据的更新都同步写入底层储存设备。rwd
:读写方式打开。文件更新都同步写入底层设备。
RandomAccessFile
依然不能向指定位置插入内容,如果移动文件指针到中间位置,则新输出的会覆盖文件中原有的内容。如果先把插入点后面的内容读入缓冲区,等新内容写入后再把缓冲区内容追加到后面便可实现。