【Java I/O 流】4 - 6 转换流
§4-6 转换流
4-6.1 字符流的转换流
转换流是字符流的高级流,是字节流与字符流之间的桥梁。其体系如图所示:
使用转换流,使得字节流和字符流通过转换流这一个桥梁相互沟通。读取数据时,先经过字节流,然后通过转换流使用字符流中的方法;写出数据时,先经过转换流,转换成字节流操作字节数据。
作用:
- 指定字符集读写数据(自 JDK 11 起被淘汰);
- 在字节流中使用字符流中的方法;
4-6.2 转换输入流
InputStreamReader
是一个从字节流转换为字符流的桥梁:它读取字节数据,并将字节数据使用指定字符集解码为对应字符。
构造方法:
构造方法 | 描述 |
---|---|
InputStreamReader(InputStream in) |
使用平台默认字符集创建一条转换输入流 |
InputStreamReader(InputStream in, String name) |
使用指定名称的字符集创建一条转换输入流 |
InputStreamReader(InputStream in, Charset cs) |
使用指定字符集创建一条转换输入流 |
InputStreamReader(InputStream in, CharsetDecoder dec) |
使用指定的字符集解码器创建一条转换输入流 |
-
转换流属于高级流,在底层依赖于基本流,其构造方法都会要求传入一个基本流对象;
为了效率,一般考虑在参数中包装基本流(
new
); -
使用转换输入流,则可以使用字符流的方法;
-
Charset
接口参数除了可以调用StandardCharsets
中所定义的字符集枚举常量外,也可以直接调用Charset
中的静态方法forName(String charsetName)
获取; -
关闭流释放资源时,只需要关闭高级流即可,方法内部会自行关闭所依赖的基本流;
替代方案:使用 InputStreamReader
指定字符集读取数据的方式,自 JDK 11 起被淘汰,现有一种替代方案,调用 FileReader
的重载构造器:
构造方法 | 描述 |
---|---|
FileReader(File file, Charset charset) |
使用指定字符集,创建一个关联指定文件的文件阅读器对象 |
FileReader(String fileName, Charset charset) |
使用指定字符集,创建一个关联指定文件的的文件阅读器对象 |
4-6.3 转换输出流
OutputStreamWriter
是一个从字符流转换到字节流的桥梁:写入的字符会根据所指定的字符集编码为字节数据。
构造方法:
构造方法 | 描述 |
---|---|
OutputStreamWriter(OutputStream out) |
适用平台默认的字符集创建一条转换输出流 |
OutputStreamWriter(OutputStream out, String charsetName) |
使用指定名称的字符集创建一条转换输出流 |
OutputStreamWriter(OutputStream out, Charset cs) |
使用指定字符集创建一条转换输出流 |
OutputStreamWriter(OutputStream out, CharsetEncoder enc) |
使用指定的字符集编码器创建一条转换输出流 |
-
转换流属于高级流,在底层依赖于基本流,其构造方法都会要求传入一个基本流对象;
为了效率,一般考虑在参数中包装基本流(
new
); -
关闭流释放资源时,只需要关闭高级流即可,方法内部会自行关闭所依赖的基本流;
替代方案:使用 OutputStreamWriter
指定字符集写出数据的方式,自 JDK 11 起被淘汰,现有一种替代方案,调用 FileWriter
的重载构造器:
构造方法 | 描述 |
---|---|
FileWriter(File file, Charset charset, boolean append) |
使用指定字符集,创建一条关联指定为文件的文件写入器 |
FileWriter(String fileName, Charset charset, boolean append) |
使用指定字符集,创建一条关联指定名称文件的文件写入器 |
4-6.4 文件转码
需求:编写一个方法,可以将文件从 GBK 转码至 UTF-8。
JDK 8 及以前的实现:
public static void oldConvert(File src) throws IOException {
Objects.requireNonNull(src);
if (!src.exists()) {
System.err.println("错误:文件不存在");
return;
} else if (src.isDirectory()) {
System.err.println("错误:不支持目录");
return;
}
//JDK 8 及以前的方案
InputStreamReader isr = new InputStreamReader(new FileInputStream(src), "GBK");
StringBuilder sb = new StringBuilder();
char[] chars = new char[10];
int len;
while ((len = isr.read(chars)) != -1) {
sb.append(chars, 0, len);
}
isr.close();
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(src.getParent() + "\\utf8file.tct"), StandardCharsets.UTF_8);
osw.write(sb.toString());
osw.close();
}
JDK 11 及以后的实现:
public static void newConvert(File src) throws IOException {
Objects.requireNonNull(src);
if (!src.exists()) {
System.err.println("错误:文件不存在");
return;
} else if (src.isDirectory()) {
System.err.println("错误:不支持目录");
return;
}
//JDK 11 起
FileReader fr = new FileReader(src, Charset.forName("GBK"));
StringBuilder sb = new StringBuilder();
char[] chars = new char[10];
int len;
while ((len = fr.read(chars)) != -1) {
sb.append(chars, 0, len);
}
fr.close();
FileWriter fw = new FileWriter(new File(src.getParent(), "utf8file.txt"), StandardCharsets.UTF_8);
fw.write(sb.toString());
fw.close();
}