Java SEFileReader读和FileWriter写乱码问题
CAMELLIA!!! note 目录
FileReader读和FileWriter写乱码问题
- 节点流(Node Streams)
- 节点流直接与数据源或数据目的地(如文件、内存、网络连接等)相连接,进行数据的读写操作。它们是真正执行IO操作的流。
- 包装流(Processing Streams)
包装流用于包装节点流或其他包装流,以提供附加功能,如缓冲、数据转换等。它们通过装饰模式增强了节点流的功能。
一、为什么FileReader读和FileWriter写会出现乱码?
在Java中,FileReader
和FileWriter
主要用于读取和写入文本文件。它们的工作方式是基于平台默认的字符编码。
这可能会导致在某些情况下出现乱码问题,尤其是在处理非ASCII字符或跨平台操作时。
1.1 出现乱码的原因主要有以下几个:
字符编码不一致:
- 如果文件的编码与
FileReader
和FileWriter
默认使用的编码不同,就会出现乱码。例如,如果文件是用UTF-8编码写入的,而FileReader
使用的是系统默认的编码(如Windows上的GBK或ISO-8859-1),读取时就会出现乱码。
跨平台编码差异:
- 不同操作系统的默认编码不同。例如,Windows系统通常默认使用GBK编码,而Linux系统通常默认使用UTF-8编码。如果在Windows上创建的文件在Linux上读取,或者反过来,而没有显式指定编码,就会出现乱码。
1.2 图解
二、如何解决FileReader读和FileWriter写出现的乱码问题?
为了避免乱码问题,可以显式指定字符编码。推荐使用InputStreamReader
和OutputStreamWriter
,它们允许指定字符编码。
InputStreamReader
是一个字符流类,它将字节输入流转换为字符输入流。其主要功能是读取字节数据并将其解码为字符数据。
- 构造方法:
InputStreamReader(InputStream in)
: 使用平台默认字符集创建InputStreamReader。
InputStreamReader(InputStream in, String charsetName)
: 使用指定字符集创建InputStreamReader。
2.2 OutputStreamWriter
OutputStreamWriter
是一个字符流类,它将字符输出流转换为字节输出流。其主要功能是将字符数据编码为字节数据并写入输出流。
- 构造方法:
OutputStreamWriter(OutputStream out)
: 使用平台默认字符集创建OutputStreamWriter。
OutputStreamWriter(OutputStream out, String charsetName)
: 使用指定字符集创建OutputStreamWriter。
2.3 读取文件时指定编码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| package com.camellia.io.garbledcharacters;
import org.junit.jupiter.api.Test;
import java.io.*; import java.nio.charset.Charset;
public class InputStreamReaderDecodingTest {
@Test public void testInputStreamReaderDecoding() { try (InputStreamReader isr = new InputStreamReader(new FileInputStream("src/document/GBK滕王阁序.txt"), "GBK")) { int readCount; char[] chars = new char[1024]; while ((readCount = isr.read(chars)) != -1) { System.out.println(new String(chars, 0, readCount)); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
@Test public void testFileReaderDecoding() { try (FileReader isr = new FileReader("src/document/GBK滕王阁序.txt", Charset.forName("GBK"))) { int readCount; char[] chars = new char[1024]; while ((readCount = isr.read(chars)) != -1) { System.out.println(new String(chars, 0, readCount)); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
|
2.4 写入文件时指定编码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| package com.camellia.io.garbledcharacters;
import org.junit.jupiter.api.Test;
import java.io.*; import java.nio.charset.Charset;
public class OutputStreamWriterEncodingTest {
@Test public void testOutputStreamWriterEncoding() { try (OutputStreamWriter osw = new OutputStreamWriter( new FileOutputStream("src/document/GBK滕王阁序out.txt", false), Charset.forName("GBK"))) { osw.write("花有从开日,人无再少年。"); osw.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
@Test public void testFileWriterEncoding() { try (FileWriter fw = new FileWriter( "src/document/GBK滕王阁序out.txt", Charset.forName("GBK"), false)) { fw.write("花有从开日,人无再少年。"); fw.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
|