因为以Android开发为主要目的,本篇博客的主要参考资料为Android Developers的文档。
Java I/O基础
Java I/O主要包括如下几个层次,包含三个部分:
- 流式部分――I/O的主体部分;
- 非流式部分――主要包含一些辅助流式部分的类,如:
File
类、RandomAccessFile
类和FileDescriptor
等类; - 其他类–文件读取部分的与安全相关的类,如:
SerializablePermission
类,以及与本地操作系统相关的文件系统的类,如:FileSystem
类和Win32FileSystem
类和WinNTFileSystem
类。流
- Java把数据传输这件事称为流。
- Java 中的 I/O流类分为输入和输出部分。通过继承
InputStream
或Reader
的类都有read()
方法,它可以读取单个字节或者字节数组。而继承OutputStream
或Writer
的类都有write()
方法,它可以写入单个字节或者字节数组。一般通过组合多个对象来提供我们期望的功能(装饰器模式)。 - Java的IO模型设计非常优秀,它使用Decorator(装饰器)模式,按功能划分Stream,可以动态装配这些Stream,以便获得需要的功能。例如,若需要一个具有缓冲的文件输入流,则应当组合使用
FileInputStream
和BufferedInputStream
。 - Java中的
InputStream
与OutputSream
提供基于字节的IO操作。 - Java中的
Reader
与Writer
以面向Unicode字符(16位,2个字节)的方式提供I/O功能。字符流的本质是基于字节流I/O时(调用了转换器)查了对应的码表。可以使用InputStreamReader
以及OutputStreamWriter
适配器将字符流转化为字节流。==Tips:==适配器是连接不匹配的二者,让以上两者变匹配的对象。此处的两个适配器要把字符流转化为字节流,所以要在具备基础IO功能的基础上实现最基础的字符流的功能,而恰好
Reader
和Writer
类是最基础的字符流,所以可以通过实现InputStream
或OutputStream
实现的接口+继承Reader
或Writer
类来实现转换。
字符流
Reader
类
Writer
类- 使用字符输出所用的抽象类,以下是子类必须实现的方法:
1
2
3
4
5
6public abstract void write(char[], int, int);//输出给定字符数组中从int起的int个字符
public abstract void flush();
//用于flush整条流。当本Writer在缓冲区里保存了字符时,立即将保存的字符都写入目的地,并且若目的地也是流,也flush它,由此可知flush()方法会清空整条流上的所有缓冲区
//若目的地为文件,则flush方法保证缓冲区中的字符都交给操作系统作写入处理,但不保证字符确实被写入物理存储设备
public abstract void close();//关闭本流,关闭前先flush它
//对已经关闭的流执行write()或flush()方法会导致抛出IOException
OutputStreamWriter
- 如前文所述是字符流转为字节流的适配器,可以指定编码或编码器,否则使用平台默认编码;未指定编码器时,对于无法映射的Unicode字符组统一使用编码的默认替代字符来替代。
- 在将字符转为字节时,亦如前文所述,会调用转换器进行字符与字节的转换。而
OutputStreamWriter
会在向底层输出流写入转换完成的字符前将其存入缓冲区,减少了写入操作频率,提升效率。注意:输入的字符没有缓冲。1
2
3public OutputStreamWriter(OutputStream)
//可选重载参数:String charsetName, 指定的编码名;Charset csn, 指定的编码;
//CharsetEncoder enc, 指定的编码器
==Tips:== 因为输入
OutputStreamWriter
的字符没有经过缓冲,为了实现最佳性能,推荐使用时在OutputStreamWriter
外包装BufferedWriter
。
BufferedWriter
- 提供适配不同环境的
newLine()
方法用于换行(并非所有平台均使用\n
进行换行); - 在输出至字符流前会先将字符存入缓冲区,提升效率。
1
2public BufferedWriter(Writer)
//可选重载参数:int sz,指定缓冲区大小
FileWriter
- 写入文件用,使用默认编码和默认字节缓冲区大小(无字符缓冲,可通过包装
BufferedWriter
来改善性能)。若想改变编码,可在FileOutputStream
上使用OutputStreamWriter
。1
2
3public FileWriter(String fileName)
//重载参数:File
//可选重载参数:boolean,true时为append模式
==Tips:== 某些平台只允许一个操作文件的对象(i.e.
FileWriter
)同时操作同一文件,容易导致抛出IOException。
PrintWriter
- 输出格式化的文本。可以指定编码。该类中实现了
PrintStream
类中的所有print*
方法以及format()
方法。不提供字节输出。 - 其构造函数包含可选
boolean
重载参数,值为true
时开启自动刷新模式,即在每个print*
方法被调用时执行flush()
方法。(默认为当输出一个换行符\n
时执行) - 除某些构造函数构造的对象外不会抛出
IOException
。需要手动调用checkError()
方法,若返回true
则说明在输出至流或在格式化字符串的过程中遇到错误。1
2
3
4
5
6
7
8
9
10public PrintWriter(Writer);
//重载参数:OutputStream, File, String fileName.
//可选重载参数:boolean,true时为自动刷新模式;String csn,指定的编码。
public
PrintWriter append(CharSequence csq)//等价于write(csq.toString()),受缓冲区的限制可能不能输出所有内容
//其他重载没有此限制
//若字符串为null,则输出"null"
protected
void clearError()//初始化checkError()检查的flag