1. Java的IO运用了
装饰者模式,提供了一个称做链接(Chaining)的机制,可以将一个流处理器跟另一个流处理器首尾相接,以其中之一的输出为输入,形成一个流管道的链接,如:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("lecturer.dat"));
2. Java的IO具有对称性:
a. 输入 - 输出对称:
字节流的两个
抽象基类:
InputStream和
OutputStream
// 输入流实现Closeable接口(close()方法)
public abstract class InputStream implements Closeable {
}
// 输出流实现Closable接口和Flushable接口(flush()方法)
public abstract class OutputStream implements Closeable, Flushable {
}
字符流的两个
抽象基类:
Reader和
Writer
// Reader实现Readable(read()方法)和Closeable接口
public abstract class Reader implements Readable, Closeable {
}
// Writer实现Appendable接口(append系列方法)、Closable接口和Flushable接口
public abstract class Writer implements Appendable, Closeable, Flushable {
}
b. 字节流 - 字符流对称:
输入流:
InputStream和
Reader分别负责字节流和字符流的输入,
输出流:
OutputStream和
Writer分别负责字节流和字符流的输出。
3. 使用完资源后,必须要手动调用
close()方法关闭,否则会导致缓冲区的部分没有写入到流而产生错误。最好是放在
finally块中,保证执行。
如果要把异常抛给调用者,省略catch从句;如果在catch中重新抛出异常会损失性能:
public InputStream decrypt(File fileIn) throws Exception {
FileInputStream fis = null;
try {
fis = new FileInputStream(fileIn);
} finally {
if (fis != null)
fis.close();
}
}
已经关闭的资源 再次调用close()不会抛异常,也不会产生任何动作。
4. 输入流和输出流之间的转换一般通过
字节数组来中转:
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(new File("eligible.txt"));
fos = new FileOutputStream(new File("eligibility.txt"));
byte[] buffer = new byte[8192];
int count = 0;
while ((count = fis.read(buffer)) > 0) {
fos.write(buffer, 0, count);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null)
fos.close();
if (fis != null)
fis.close();
}
5. 字节流和字符流之间的转换:
InputStreamReader,
OutputStreamWriter。
FileInputStream fis = null;
InputStreamReader isr = null;
FileOutputStream fos = null;
OutputStreamWriter osw = null;
try {
fis = new FileInputStream(new File("eligible.txt"));
fos = new FileOutputStream(new File("eligibility.txt"));
// Char reader wraps the byte input stream. It's preferable to specify the char set.
// Otherwise messy code may occur.
// Available char set: ASCII, UNICODE, GB2312, GBK, UTF-8, UTF-16, UTF-32
isr = new InputStreamReader(fis, "UTF-8");
// Char writer wraps the byte output stream. It's preferable to specify the char set.
// Otherwise messy code may occur.
osw = new OutputStreamWriter(fos, "UTF-8");
char[] buffer = new char[1024];
int count = 0;
while ((count = isr.read(buffer)) > 0) {
osw.write(buffer, 0, count);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (isr != null)
isr.close();
if (osw != null)
osw.close();
}
6. 底层的流一定是字节流,字符流不过是在其基础上按照编码进行了处理。
7. 使用缓冲类
BufferedInputStream,
BufferedOutputStream,
BufferedReader或
BufferedWriter来提升性能:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("neglect.dat"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("negligible.dat"));
BufferedReader br = new BufferedReader(new FileReader("elect.dat"));
BufferedWriter bw = new BufferedWriter(new FileWriter("election.dat"));
8. 扩展
FilterInputStream,
FilterOutputStream,
FilterReader或
FilterWriter来实现自定义的输入输出流处理类。
9. 如果文件路径包含特殊字符(如空格)经过编码后(%20)传给FileInputStream,会抛出java.io.FileNotFoundException:
// String path = SpecialCaseInPath.class.getProtectionDomain().getCodeSource().getLocation().getPath() + "/..\\screw chew.xml"; // This long expression would bring the encoded path
String path = "C:\\programs%20data\\screw chew.xml";
FileInputStream fis = new FileInputStream(path);
解决办法:
// Solution 1:
// path = path.replaceAll("%20", " ");
// Solution 2:
path = URLDecoder.decode(path, "utf-8");
FileInputStream fis = new FileInputStream(path);