Java基础 Java-IO流 深入浅出 (5)

同时操作多个AutoCloseable资源时,在try(resource) { ... }语句中可以同时写出多个资源,用;隔开。例如,同时读写两个文件:

// 读取input.txt,写入output.txt: try (InputStream input = new FileInputStream("input.txt"); OutputStream output = new FileOutputStream("output.txt")) { input.transferTo(output); // transferTo的作用是? } Reader

Reader是Java的IO库提供的另一个输入流接口。和InputStream的区别是,InputStream是一个字节流,即以byte为单位读取,而Reader是一个字符流,即以char为单位读取:

InputStream Reader
字节流,以byte为单位   字符流,以char为单位  
读取字节(-1,0~255):int read()   读取字符(-1,0~65535):int read()  
读到字节数组:int read(byte[] b)   读到字符数组:int read(char[] c)  

java.io.Reader是所有字符输入流的超类,它最主要的方法是:

public int read() throws IOException; FileReader

FileReader是Reader的一个子类,它可以打开文件并获取Reader。下面的代码演示了如何完整地读取一个FileReader的所有字符:

public void readFile() throws IOException { // 创建一个FileReader对象: Reader reader = new FileReader("src/readme.txt"); // 字符编码是??? for (;;) { int n = reader.read(); // 反复调用read()方法,直到返回-1 if (n == -1) { break; } System.out.println((char)n); // 打印char } reader.close(); // 关闭流 }

如果我们读取一个纯ASCII编码的文本文件,上述代码工作是没有问题的。但如果文件中包含中文,就会出现乱码,因为FileReader默认的编码与系统相关,例如,Windows系统的默认编码可能是GBK,打开一个UTF-8编码的文本文件就会出现乱码。

要避免乱码问题,我们需要在创建FileReader时指定编码:

Reader reader = new FileReader("src/readme.txt", StandardCharsets.UTF_8);

和InputStream类似,Reader也是一种资源,需要保证出错的时候也能正确关闭,所以我们需要用try (resource)来保证Reader在无论有没有IO错误的时候都能够正确地关闭:

try (Reader reader = new FileReader("src/readme.txt", StandardCharsets.UTF_8) { // TODO }

Reader还提供了一次性读取若干字符并填充到char[]数组的方法:

public int read(char[] c) throws IOException

它返回实际读入的字符个数,最大不超过char[]数组的长度。返回-1表示流结束。

利用这个方法,我们可以先设置一个缓冲区,然后,每次尽可能地填充缓冲区:

public void readFile() throws IOException { try (Reader reader = new FileReader("src/readme.txt", StandardCharsets.UTF_8)) { char[] buffer = new char[1000]; int n; while ((n = reader.read(buffer)) != -1) { System.out.println("read " + n + " chars."); } } } 小结

Reader定义了所有字符输入流的超类:

FileReader实现了文件字符流输入,使用时需要指定编码;

CharArrayReader和StringReader可以在内存中模拟一个字符流输入。

Reader是基于InputStream构造的:可以通过InputStreamReader在指定编码的同时将任何InputStream转换为Reader。

总是使用try (resource)保证Reader正确关闭。

Writer

Reader是带编码转换器的InputStream,它把byte转换为char,而Writer就是带编码转换器的OutputStream,它把char转换为byte并输出。

Writer和OutputStream的区别如下:

OutputStream Writer
字节流,以byte为单位   字符流,以char为单位  
写入字节(0~255):void write(int b)   写入字符(0~65535):void write(int c)  
写入字节数组:void write(byte[] b)   写入字符数组:void write(char[] c)  
无对应方法   写入String:void write(String s)  

Writer是所有字符输出流的超类,它提供的方法主要有:

写入一个字符(0~65535):void write(int c);

写入字符数组的所有字符:void write(char[] c);

写入String表示的所有字符:void write(String s)。

FileWriter

FileWriter就是向文件中写入字符流的Writer。它的使用方法和FileReader类似:

try (Writer writer = new FileWriter("readme.txt", StandardCharsets.UTF_8)) { writer.write('H'); // 写入单个字符 writer.write("Hello".toCharArray()); // 写入char[] writer.write("Hello"); // 写入String } 小结

Writer定义了所有字符输出流的超类:

FileWriter实现了文件字符流输出;

CharArrayWriter和StringWriter在内存中模拟一个字符流输出。

使用try (resource)保证Writer正确关闭。

Writer是基于OutputStream构造的,可以通过OutputStreamWriter将OutputStream转换为Writer,转换时需要指定编码。

Filter 模式

又称装饰者模式

定义:动态给一个对象添加一些额外的职责,就象在墙上刷油漆.使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjsjf.html