Java FileReader编码问题


130

我尝试使用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 []的复制。还要用StringBuilder替换StringBuffer。这些都不是关于您的问题的,尽管。
Joachim Sauer,2009年

1
我不想这么说,但是您在粘贴部分之后立即阅读JavaDoc吗?您知道吗,该部分说“要自己指定这些值,请在FileInputStream上构造一个InputStreamReader。”?
Powerlord

感谢您的评论,实际上我阅读了JavaDoc,但是不确定的是我是否应该自己指定这些值,然后切换到“在FileInputStream上构造InputStreamReader”。
尼龙

是的,如果您知道文件使用的不是平台默认编码,则必须告诉InputStreamReader使用哪个文件。
艾伦·摩尔

Answers:


247

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

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

不,没有一般的方法可以猜测任何给定“纯文本”文件的编码。

一参数的构造函数FileReader始终使用平台默认编码,这通常是一个坏主意

由于Java 11 FileReader还获得了接受编码的构造函数:new FileReader(file, charset)new FileReader(fileName, charset)

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


1
InputStream是= new FileInputStream(filename); 在这里,我得到的错误文件找不到带有俄语文件名的错误
Bhanu Sharma

3
+1表示使用InputStreamReader的建议,但是,如果可以更改代码,则在代码块中使用链接会使复制和粘贴代码变得困难,谢谢
Ferrybig 2015年

1
在编码中是“ UTF-8”还是“ UTF8”。根据有关编码的Java SE参考,由于InputStreamReaderjava.io类,因此它将是“ UTF8”吗?
NobleUplift

9
@NobleUplift:最安全的选择是StandardCharsets.UTF_8,那里不可能有错别字;-)但是,是的,如果您使用弦乐"UTF8"将是正确的(尽管我似乎记得它会接受两种方式)。
Joachim Sauer

1
@JoachimSauer实际上,这是的目的之一Byte Order Mark,以及..建立字节顺序!:)因此,我发现Java的FileReader无法自动检测具有这样的BOM的UTF-16感到很奇怪...事实上,我曾经写过一个UnicodeFileReader做到这一点的工具。不幸的是关闭了源代码,但是Google拥有非常相似的UnicodeReader
Stijn de Witt

79

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

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


24
“对API的重大监督”-感谢您的解释-我想知道为什么找不到我想要的构造函数!干杯约翰
monojohnny

@Bhanu Sharma:这是一个不同级别的编码问题,请检查您从哪里获取文件名,以及是否对其进行了硬编码,编译器使用的是哪种编码。
Michael Borgwardt'2

1
@BhanuSharma:文件名编码问题与此问题无关。请参阅许多现有的“为什么Unicode文件名不能在Java中工作”问题之一。剧透:像FileReader这样的java.io API使用C标准库文件系统调用,这些调用在Windows上不支持Unicode;考虑改用java.nio。
bobince

1
FileReader使用Java的平台默认编码,该编码取决于运行它的计算机的系统设置,通常是该区域设置中用户中最受欢迎的编码。” 我不会那样说。至少是Windows。出于一些奇怪的技术/历史原因,JVM忽略了以下事实:Unicode是Windows上“所有新应用程序” 的推荐编码,而是始终充当配置为旧应用程序的后备的旧编码是“平台默认值”。
Stijn de Witt

6
我什至可以说,如果您的Java应用程序在每次读取或写入文件/流/资源时没有明确指定编码,那么它就坏了,因为那时它永远无法可靠地工作。
Stijn de Witt


6

对于Java 7+ 文档,您可以使用以下命令:

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

这是所有字符集文档

例如,如果您的文件位于CP1252中,则使用此方法

Charset.forName("windows-1252");

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

如果您不知道文件中的确切编码,则可以使用一些第三方libs,例如Google提供的工具,它工作得很整齐。


1

使用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();
}

0

对于另一种拉丁语言(例如西里尔字母),您可以使用以下代码:

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.