Hike News
Hike News

Java-IO(二)输入输出流体系

输入输出流体系

处理流的用法

使用处理流来包装节点流,程序通过处理流来执行输入输出,让节点流与底层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
2
InputStreamReader reader = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(reader);

推回输入流

在IO流体系中有两个流比较特殊,PushbackInputStreamPushbackReader,它们都提供如下三个方法:

  • voidunread(byte[]/char[] buf):将一个字节/字符数组内容推入缓冲区,从而能重复读取刚刚读取的内容。
  • void unread(byte[]/char[] b,int off,int len):将一个字节/字符数组里从off开始,长度为len字节/字符内容推入缓冲区,从而允许重复读取。
  • void unread(int b):将一个字节/字符推入缓冲区,从而允许重复读取。

这三个方法与InputStreamReader中的三个方法相对应,它们各有一个推回缓冲区,当调用unread()方法时,系统会把指定数组内容推回缓冲区,并且每次调用read()方法时总是从推回缓冲区读取。当完全读取缓冲区内容后,但还没有装满read()的存放数组时才会从输入流中读取。当创建PushbackInputStreamPushbackReader时需要指定缓冲区大小,而默认大小为1。如果超出大小将会引发IO异常。

重定向输入输出

Java的标准输入/输出分别通过System.inSystem.out代表,获取输入和输出,输出是输出到屏幕上。在System类下有如下三个重定向的方法:

  • static void setErr(PrintStream err):重定向标准错误输出流。
  • static void setIn(InputStream in):重定向标准输入流。
  • static void setOut(PrintStream out):重定向标准输出流。
1
2
PrintStream p = new PrintStream(new FileOutputStream("out.txt"));
System.setOut(p);

以上代码重定向输出流到一个文本文件中,所以输出时将不会输出到屏幕上,而到了文件中。同样也可以重定向输入,指定从文件输入。

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依然不能向指定位置插入内容,如果移动文件指针到中间位置,则新输出的会覆盖文件中原有的内容。如果先把插入点后面的内容读入缓冲区,等新内容写入后再把缓冲区内容追加到后面便可实现。