【问题标题】:Java FileReader encoding issueJava FileReader 编码问题
【发布时间】: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 使用哪一个。

标签: java file unicode encoding


【解决方案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();
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-11-12
          • 2017-01-28
          相关资源
          最近更新 更多