Java应用程序:无法读取ISO

我有一个编码为iso-8859-1的文件,并且包含诸如ô的字符。

我正在用java代码读取此文件,如下所示:

File in = new File("myfile.csv");
InputStream fr = new FileInputStream(in);
byte[] buffer = new byte[4096];
while (true) {
    int byteCount = fr.read(buffer, 0, buffer.length);
    if (byteCount <= 0) {
        break;
    }

    String s = new String(buffer, 0, byteCount,"ISO-8859-1");
    System.out.println(s);
}

然而,ô字符总是乱码,通常打印为? 。

我已经阅读了这个主题(并在路上学到了一些),例如

  • http://www.joelonsoftware.com/articles/Unicode.html
  • http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058
  • http://www.ingrid.org/java/i18n/utf-16/
  • 但仍然无法得到这个工作

    有趣的是,这适用于我的本地电脑(XP),但不是在我的Linux机器上。

    我检查了我的jdk支持所需的字符集(它们是标准的,所以这不是令人惊奇的)使用:

    System.out.println(java.nio.charset.Charset.availableCharsets());
    

    我怀疑你的文件实际上没有被编码为ISO-8859-1,或者System.out不知道如何打印字符。

    我建议检查第一个,检查文件中的相关字节。 要检查第二个,请检查字符串中的相关字符,并将其打印出来

     System.out.println((int) s.getCharAt(index));
    

    在这两种情况下,结果应该是244小数; 0xf4十六进制。

    请参阅我的关于Unicode调试的文章,以获取常规建议(所提供的代码使用C#,但很容易转换为Java,原理相同)。

    一般来说,顺便说一下,我会用正确的编码将InputStreamReader封装到流中 - 这比“手动”创建新字符串更容易。 我意识到这可能只是演示代码。

    编辑:这是一个非常简单的方法来证明控制台是否可以工作:

     System.out.println("Here's the character: u00f4");
    

    将文件解析为固定大小的字节块并不好 - 如果某些字符具有横跨两个块的字节表示,该怎么办? 改用适当的字符编码来使用InputStreamReader

     BufferedReader br = new BufferedReader(
             new InputStreamReader(
             new FileInputStream("myfile.csv"), "ISO-8859-1");
    
     char[] buffer = new char[4096]; // character (not byte) buffer 
    
     while (true)
     {
          int charCount = br.read(buffer, 0, buffer.length);
    
          if (charCount == -1) break; // reached end-of-stream 
    
          String s = String.valueOf(buffer, 0, charCount);
          // alternatively, we can append to a StringBuilder
    
          System.out.println(s);
     }
    

    顺便说一句,记得检查确实可以正确显示unicode字符。 您也可以将程序输出重定向到一个文件,然后将其与原始文件进行比较。

    正如Jon Skeet所说,问题也可能与控制台有关。 尝试System.console().printf(s)以查看是否有区别。


    @Joel - 你自己的答案证实了这个问题是你的操作系统上的默认编码(UTF-8,一个Java选取的)和你的终端使用的编码(ISO-8859-1)之间的差异。

    考虑这个代码:

    public static void main(String[] args) throws IOException {
        byte[] data = { (byte) 0xF4 };
        String decoded = new String(data, "ISO-8859-1");
        if (!"u00f4".equals(decoded)) {
            throw new IllegalStateException();
        }
    
        // write default charset
        System.out.println(Charset.defaultCharset());
    
        // dump bytes to stdout
        System.out.write(data);
    
        // will encode to default charset when converting to bytes
        System.out.println(decoded);
    }
    

    默认情况下,我的Ubuntu(8.04)终端使用UTF-8编码。 通过这种编码,可以打印:

    UTF-8
    2 O

    如果我将终端的编码切换到ISO 8859-1,则会打印:

    UTF-8
    ôÃ'

    在这两种情况下,Java程序都会发送相同的字节:

    5554 462d 380a f4c3 b40a
    

    唯一的区别在于终端如何解释它收到的字节。 在ISO 8859-1中,ô编码为0xF4。 在UTF-8中,ô编码为0xC3B4。 其他字符对于这两种编码都是通用的。

    链接地址: http://www.djcxy.com/p/66117.html

    上一篇: Java App : Unable to read iso

    下一篇: ASP.NET Core Application Logs Not Written To Blob in Azure App Service