概述
Java 的 I/O 操作类在包 java.io 下,大概有将近 80 个类,但是这些类大概可以分成四组,分别是:
- 基于字节操作的 I/O 流接口:
InputStream
和OutputStream
- 基于字符操作的 I/O 流接口:
Writer
和Reader
- 基于磁盘操作的 I/O 文件接口:
File
参考: 深入分析 Java I/O 的工作机制 @ref
流
按照流操作对象的类型是字节还是字符, 分为字节流和字符流
- 字节流的父类是
InputStream
/OutputStream
, 读写单个字节/字节数组, - 字符流的父类是
Reader
/Writer
用于读写被编码(GBK/UTF8)的字符串, 读写Char/Char数组;
按照功能分为节点流(node stream)和过滤流(filter stream, 或者叫装饰流)
- 节点流用来处理从基本位置获取字节(文件, 内存, 管道),
FileInputStream
,ByteArrayInputStream
,PipedInputStream
, 这些类提供基本的读写方法; - 过滤流用于包装节点流, 提供了新的方法, 可以更方便的读写高级类型的数据(类序列化, 压缩文件, Java基本类型)
ObjectInputStream
,ZipInputStream
,DataInputStream
.
节点流 & 过滤流
图-外层的DataInputStream(过滤流)提供了额外的方法:
字节流 & 字符流
字符流相关类以及继承关系:
字符流 |
字节流相关类以及继承关系:
字节流 |
字节流 常用类和方法
InputStream
/OutputStream
提供基本的字符/字符数组读写InputStream.available()
: 返回可读的字节数read()
,read(byte[])
: 阻塞的, read返回读取的一个字节(int)write(int b)
,write(byte[])
: 阻塞的close()
FileInputStream
/FileOutputStream
ByteArrayInputStream
/ByteArrayOutputStream
: 包含一个内部缓冲区(字节数组), 该缓冲区包含从流中读取的字节PipedInputStream
/PipedOutputStream
同上BufferedInputStream
/BufferedOutputStream
: 为另一个流提供缓冲ObjectInputStream
/ObjectOutputStream
Object readObject()
void writeObject(Object)
字符流 常用类和方法
- Reader: 提供对char,char[],String类型数据的基本操作
read()
: 返回字符的Unicode编码(0-65535,双字节范围), 到达流末尾返回-1;read(char[])
: 读取字符到数组并返回已读取的字符个数;skip(long n)
: 跳过n个charmark(int limit)
: 为流的当前位置增加标记, 下次调用reset可以返回这个标记, 如果调用mark()后读取字符数超过limit, 下次调用reset会失败.reset()
:close()
:
- InputStreamReader
getEncoding()
: 获取输入流的编码ready()
: 如果有数据可读, 返回true
- FileReader: 继承自 InputStreamReader
- 构造器:
FileReader(String)
,FileReader(java.io.File)
- 构造器:
- BufferedReader:
readLine()
: 读取一行并返回字符串(不包括换行符), 如果流已经读尽则返回null
- Scanner: 不是继承自Reader
- Writer : 提供对char,char[],String类型数据的基本操作
write(char c)
,write(char[])
,write(String)
append(char)
,append(CharSequence)
flush()
: 让缓冲区的内容立刻写入close()
:
- PrintWriter:
文件
本章主要介绍文件操作类: java.io.File
和 java.io.RandomAccessFile
java.io.File
File 是“文件”和“目录路径名”的抽象表示形式。File 直接继承于Object,实现了Serializable接口和Comparable接口。
实现Serializable接口,意味着File对象支持序列化操作。
实现Comparable接口,意味着File对象之间可以比较大小;File能直接被存储在有序集合(如TreeSet、TreeMap中)。
public class FileTest { |
java.io.RandomAccessFile
java.io.RandomAccessFile
是随机访问文件(包括读/写)的类。它支持对文件随机访问的读取和写入,即我们可以从指定的位置读取/写入文件数据。
需要注意的是,RandomAccessFile 虽然属于java.io包,但它不是InputStream或者OutputStream的子类;
它也不同于FileInputStream和FileOutputStream。 FileInputStream 只能对文件进行读操作,而FileOutputStream 只能对文件进行写操作;
RandomAccessFile 同时支持文件的读和写,并且它支持随机访问。
RandomAccessFile
大部分功能被JDK1.4中NIO的内存映射文件替代了
RandomAccessFile raf = new RandomAccessFile(args[0], "r"); |
try-with-resources
旧风格的I/O操作的异常捕获:
private static void printFile() throws IOException { |
上面代码中可能会抛出异常. try语句块中有3个地方能抛出异常, finally语句块中有一个地方会能出异常.
不论try语句块中是否有异常抛出, finally语句块始终会被执行.这意味着, 不论try语句块中发生什么, InputStream 都会被关闭, 或者说都会试图被关闭.如果关闭失败, InputStream’s close()方法也可能会抛出异常.
Q: 假设try语句块抛出一个异常, 然后finally语句块被执行.同样假设finally语句块也抛出了一个异常.那么哪个异常会根据调用栈往外传播?
A: 即使try语句块中抛出的异常与异常传播更相关, 最终还是finally语句块中抛出的异常会根据调用栈向外传播.
在JDK7中, try-with-resources 风格的IO异常捕获:
try-with-resources语句会确保在try语句结束时关闭所有资源. 实现了java.lang.AutoCloseable
或java.io.Closeable
的对象都可以做为在try()
代码块内打开的资源, 并且可以在退出try()
语句块时被自动关闭.
// try()代码块内打开多个资源: |
当try-with-resources结构中抛出一个异常, 同时资源调用close方法时也抛出一个异常, try-with-resources结构中抛出的异常会向外传播, 而资源被关闭时抛出的异常被抑制了. 这与旧风格代码的例子相反.
API Example
字节流 API Example
/* 基本字节流 InputStream/OutputStream 接口测试: */ |
字符流 API Example
/* PrintWriter and Scanner */ |