1. 字符流
1.1 什么是字符流
在Java中,字符流是指提供了基于字符的I/O能力的API。
Java 1.0中提供的基于字节的I/O流API只能支持8位字节流,无法妥善地处理16位Unicode字符。由于需要支持Unicode处理国际化字符,因此Java 1.1 对基础流式I/O库进行了重大的修改,核心是增加了字符流相关的API,处理国际化Unicode字符的编码和解码。
字符流是以字符(char)为单位读写数据的:一次处理一个 Unicode。字符流的底层仍然是基本的字节流,它封装了字符的编码解码算法。
字符流以Reader和Writer为核心抽象类,所有的字符输入流类均继承Reader,所有的字符输出流均继承Writer。如下图所示:
字符流相关子类可以分为节点流和处理流:上图中带阴影的是节点流,不带阴影的是处理流。
1.2 FileWriter示例
编写代码,使用FileWriter将字符写入文件。代码示意如下:
package api_04;
import java.io.FileWriter;
import java.io.Writer;
public class WriterDemo1 {
public static void main(String[] args){
Writer writer = null;
try{
writer = new FileWriter("./src/api_04/demo");
writer.write("Hello World!\n");
writer.write("Hello FileWriter!\n");
}catch (Exception e){
e.printStackTrace();
}finally {
if (writer != null){
try{
writer.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
1.3 FileReader示例
- 编写代码,使用FileReader从文件中读取字符。代码示意如下:
package api_04;
import java.io.FileReader;
import java.io.Reader;
public class ReaderDemo1 {
public static void main(String[] args) {
Reader reader = null;
try{
reader = new FileReader("./src/api_04/demo");
char[] data = new char[5];
int len = 0;
while (len !=-1){
System.out.print(new String(data,0,len));
len = reader.read(data);
}
}catch (Exception e){
e.printStackTrace();
}finally {
if (reader != null){
try{
reader.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
1.4 try-with-resources语法
在前面的案例中,为了妥善的处理I/O操作中可能出现的异常,并保证在程序结束后关流,我们使用了try-catch-finally语句块。但在实际编码中遇到很多不方便的情况,例如:
- finally语句块不能访问try语句块中声明的变量
- finally语句块中需要再次添加try-catch语句块
幸好Java 7 引入了try-with-resources语法,可以很好地简化上述代码。
这种称为try-with-resources语法。其要求为:
1、try后面的括号称为资源说明头,用于创建语句块中使用的资源对象
2、资源说明头中创建的对象必须实现java.lang.AutoCloseable接口,该接口只有一个方法-close()
3、资源说明头中可以包含多个创建对象的语句,用分号隔开,最后的分号可以省略
4、不论如何退出try语句块,都会自动调用所有资源对象的close方法
5、退出try语句块时,会以与声明资源对象相反的顺序去调用资源对象的close方法
编写代码,测试try-with-resources的用法。代码示意如下:
package api_04;
import java.io.Closeable;
import java.io.IOException;
public class TWRDemo {
public static void main(String[] args) {
try(
MyStream1 stream1 = new MyStream1();
MyStream2 stream2 = new MyStream2();
){
System.out.println("try...");
}catch (Exception e){
e.printStackTrace();
}
}
}
class MyStream1 implements Closeable{
@Override
public void close() throws IOException {
System.out.println("MyStream1 close...");
}
}
class MyStream2 implements Closeable{
@Override
public void close() throws IOException {
System.out.println("MyStream2 close...");
}
}
2. 字符缓冲流
2.1 字符缓冲流概述
BufferedReader和BufferedWriter分别是字符输入流和字符输出流对应的缓冲流,内置了缓冲区,通过缓冲区来减少实际的物理读写操作,进而提高读写效率。这两个类默认的缓冲区大小均为8192个字符,并支持通过构造器来设置缓冲区大小。
BufferedReader中还提供了一些增强的I/O操作方法,例如:
- readLine:读取文本中的一行内容,以'\n','\r'来识别,返回的内容不包含换行符
- skip:跳过指定数量的字符
BufferedWriter中没有提供相似的writeLine方法,但是提供了newLine方法,调用时可以向流中输出一个换行符,以达到换行的效果。
2.2 BufferedWriter示例
编写代码,测试BufferedWriter的用法。代码示意如下:
package api_04;
import java.io.*;
public class BufferedWriterDemo {
public static void main(String[] args) {
try(
Writer writer = new FileWriter("./src/api_04/demo2");
BufferedWriter bufferedWriter = new BufferedWriter(writer);
){
bufferedWriter.write("Hello world!");
bufferedWriter.newLine();
bufferedWriter.write("Hello BufferedWriter!");
bufferedWriter.newLine();
}catch (Exception e){
e.printStackTrace();
}
}
}
2.3 BufferedReader示例
编写代码,测试BufferedReader的用法。代码示意如下:
package api_04;
import java.io.*;
public class BufferedReaderDemo {
public static void main(String[] args) {
try(
Reader reader = new FileReader("./src/api_04/demo2");
BufferedReader bufferedReader = new BufferedReader(reader);
){
String line = bufferedReader.readLine();
while (line!=null) {
System.out.println(line);
line = bufferedReader.readLine();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
3. 转换流
3.1 转换流概述
转换流用于实现字节流和字符流之间的转换。
InputStreamReader是字节输入流到字符输入流的桥梁,用于将InputStream转换为Reader,可以读取字节数据并根据指定的字符集转换为字符数据。
OutputStreamWriter是字符输出流到字节输出流的桥梁,用于将OutputStream转换为Writer,可以根据指定的字符集将写出的字符数据转换为字节数据。
3.2 指定字符编码
InputStreamReader 的构造方法允许设置字符集
- InputStreamReader(InputStream in,String charsetName):基于给定的字节输入流以及字符编码创建
- InputStreamReader(InputStream in):该构造方法会根据系统默认字符集创建
OutputStreamWriter 的构造方法:
- OutputStreamWriter(OutputStream out,String charsetName):基于给定的字节输出流以及字符编码创建
- OutputStreamWriter(OutputStream out):该构造方法会根据系统默认字符集创建
3.3 OutputStreamWriter示例
编写代码,测试OutputStreamWriter的用法,并指定字符编码。代码示意如下:
package api_04;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
public class OutputStreamWriterDemo {
public static void main(String[] args) {
try(
FileOutputStream fos
= new FileOutputStream("./src/api_04/demo3");
OutputStreamWriter osw
= new OutputStreamWriter(fos,"utf-8");
BufferedWriter bw = new BufferedWriter(osw)
){
bw.write("世界你好!");
bw.newLine();
bw.write("转换流你好!");
bw.newLine();
System.out.println("写出完毕!");
}catch (Exception e){
e.printStackTrace();
}
}
}
3.4 InputStreamReader示例
编写代码,测试InputStreamReader的用法,并指定字符编码。代码示意如下:
package api_04;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
public class InputStreamReaderDemo {
public static void main(String[] args) {
try(
FileInputStream fis
= new FileInputStream("./src/api_04/demo3");
InputStreamReader isr
= new InputStreamReader(fis,"utf-8");
BufferedReader br = new BufferedReader(isr);
){
String line =br.readLine();
while(line!=null){
System.out.println(line);
line = br.readLine();
}
}catch (Exception e){
e.printStackTrace();
}
}
}