Java FileReader 编码问题

Posted

技术标签:

【中文标题】Java FileReader 编码问题【英文标题】:Java FileReader encoding issue 【发布时间】:2010-10-16 08:20:00 【问题描述】:

我尝试使用 java.io.FileReader 读取一些文本文件并将它们转换为字符串,但我发现结果编码错误,根本不可读。

这是我的环境:

Windows 2003,操作系统编码:CP1252

Java 5.0

我的文件是 UTF-8 编码或 CP1252 编码的,其中一些(UTF-8 编码文件)可能包含中文(非拉丁)字符。

我使用以下代码来完成我的工作:

   private static String readFileAsString(String filePath)
    throws java.io.IOException
        StringBuffer fileData = new StringBuffer(1000);
        FileReader reader = new FileReader(filePath);
        //System.out.println(reader.getEncoding());
        BufferedReader reader = new BufferedReader(reader);
        char[] buf = new char[1024];
        int numRead=0;
        while((numRead=reader.read(buf)) != -1)
            String readData = String.valueOf(buf, 0, numRead);
            fileData.append(readData);
            buf = new char[1024];
        
        reader.close();
        return fileData.toString();
    

上面的代码不起作用。我发现 FileReader 的编码是 CP1252,即使文本是 UTF-8 编码的。但是 java.io.FileReader 的 JavaDoc 说:

这个类的构造函数假设 即默认字符编码 并且默认的字节缓冲区大小是 合适。

这是否意味着如果我使用 FileReader,我不需要自己设置字符编码?但是我目前确实得到了错误编码的数据,处理我的情况的正确方法是什么?谢谢。

【问题讨论】:

您还应该在循环中松开 String.valueOf() 并直接使用 StringBuffer.append(char[],int,int)。这样可以节省大量 char[] 的复制。还将 StringBuffer 替换为 StringBuilder。不过,这些都与您的问题无关。 我不想这么说,但是您在粘贴的部分之后阅读了 JavaDoc 吗?你知道,“要自己指定这些值,请在 FileInputStream 上构造一个 InputStreamReader。”的部分? 感谢您的评论,实际上我阅读了 JavaDoc,但我不确定是否应该自己指定这些值,并切换到“在 FileInputStream 上构造 InputStreamReader”。跨度> 是的,如果你知道文件不是平台默认编码,你必须告诉 InputStreamReader 使用哪一个。 【参考方案1】:

是的,您需要指定要读取的文件的编码

是的,这意味着您必须知道要读取的文件的编码。

不,没有通用方法猜测任何给定“纯文本”文件的编码。

The one-arguments constructors of FileReader 始终使用平台默认编码,这通常是个坏主意

从 Java 11 开始,FileReader 也获得了接受编码的构造函数:new FileReader(file, charset)new FileReader(fileName, charset)

在java早期版本中,需要使用new InputStreamReader(new FileInputStream(pathToFile), <encoding>)

【讨论】:

InputStream is = new FileInputStream(filename);在这里我得到错误文件未找到错误与俄语文件名 +1 建议使用 InputStreamReader,但是在代码块中使用链接会导致难以复制和粘贴代码,如果可以更改,谢谢 在编码中是“UTF-8”还是“UTF8”。根据the Java SE reference on encoding,由于InputStreamReaderjava.io 类,它会是“UTF8”? @NobleUplift:最安全的赌注是StandardCharsets.UTF_8,那里不可能打错;-) 但是,如果你使用字符串"UTF8" 是正确的(尽管我似乎记得它将接受两种方式)。 @JoachimSauer 实际上,这是Byte Order Mark 的目的之一,以及.. 好吧.. 建立字节顺序! :) 因此,我发现 Java 的 FileReader 无法自动检测具有这种 BOM 的 UTF-16 很奇怪……事实上,我曾经写过一个 UnicodeFileReader 就是这样做的。不幸的是封闭源代码,但谷歌有它的UnicodeReader,非常相似。【参考方案2】:

FileReader 使用 Java 的平台默认编码,这取决于运行它的计算机的系统设置,并且通常是该区域用户中最流行的编码。

如果这个“最佳猜测”不正确,那么您必须明确指定编码。不幸的是,FileReader 不允许这样做(API 中的主要疏忽)。相反,您必须使用 new InputStreamReader(new FileInputStream(filePath), encoding) 并最好从有关文件的元数据中获取编码。

【讨论】:

“API 中的重大疏忽” - 感谢您的解释 - 我想知道为什么我找不到我想要的构造函数!干杯约翰 @Bhanu Sharma:这是一个不同级别的编码问题,请检查您从哪里获取文件名,以及是否硬编码编译器使用的编码。 @BhanuSharma:文件名编码问题与这个问题无关。查看许多现有的“为什么 Unicode 文件名在 Java 中不起作用”问题之一。剧透:像 FileReader 这样的 java.io API 使用 C 标准库文件系统调用,在 Windows 上不支持 Unicode;考虑改用 java.nio。 "FileReader 使用 Java 的平台默认编码,这取决于运行它的计算机的系统设置,并且通常是该地区用户中最流行的编码。"我不会这么说的。至少是 Windows。由于一些奇怪的技术/历史原因,JVM 忽略了 Unicode 是 Windows 上“所有新应用程序”的recommended 编码这一事实,而是 总是 就像旧编码配置为一样 旧版应用的回退是“平台默认设置”。 我什至会说,如果您的 Java 应用程序没有在每次读取或写入文件/流/资源时明确指定编码,它就是 坏了,因为它永远无法可靠地工作。【参考方案3】:

从 Java 11 开始,您可以使用它:

public FileReader(String fileName, Charset charset) throws IOException;

【讨论】:

【参考方案4】:

对于 Java 7+ doc 你可以使用这个:

BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8);

这里是所有字符集doc

例如,如果您的文件在 CP1252 中,请使用 method

Charset.forName("windows-1252");

这里是 IO 和 NIO 的 Java 编码的其他规范名称doc

如果您不知道文件中的确切编码,您可以使用一些第三方库,例如来自 Google this 的这个工具,它工作得相当简洁。

【讨论】:

【参考方案5】:

对于另一种拉丁语言,例如西里尔语,您可以使用如下内容:

FileReader fr = new FileReader("src/text.txt", StandardCharsets.UTF_8);

并确保您的.txt 文件以UTF-8(但不是默认的ANSI)格式保存。干杯!

【讨论】:

【参考方案6】:

带 InputStreamReader 的 FileInputStream 比直接使用 FileReader 更好,因为后者不允许你指定编码字符集。

这里是一个使用 BufferedReader、FileInputStream 和 InputStreamReader 的例子,这样你就可以从文件中读取行。

List<String> words = new ArrayList<>();
List<String> meanings = new ArrayList<>();
public void readAll( ) throws IOException
    String fileName = "College_Grade4.txt";
    String charset = "UTF-8";
    BufferedReader reader = new BufferedReader(
        new InputStreamReader(
            new FileInputStream(fileName), charset)); 

    String line; 
    while ((line = reader.readLine()) != null)  
        line = line.trim();
        if( line.length() == 0 ) continue;
        int idx = line.indexOf("\t");
        words.add( line.substring(0, idx ));
        meanings.add( line.substring(idx+1));
     
    reader.close();

【讨论】:

以上是关于Java FileReader 编码问题的主要内容,如果未能解决你的问题,请参考以下文章

使用 javascript 的 FileReader 获取/设置文件编码

一个小小的Java编码集问题,搞了一天,罪过

Java的文件读写操作

Java 使用流读文本数据时乱码 解决方法

JavaScript 之 FileReader简介以及原生uniapp如何将文件转成base64编码字符串示例

JavaScript 之 FileReader简介以及原生uniappvue如何将文件转成base64编码字符串示例