当前位置:  开发笔记 > 编程语言 > 正文

Java App:无法正确读取iso-8859-1编码文件

如何解决《JavaApp:无法正确读取iso-8859-1编码文件》经验,为你挑选了3个好方法。

我有一个编码为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());

Jon Skeet.. 14

我怀疑您的文件实际上并未编码为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");


Zach Scriven.. 9

将文件解析为固定大小的字节块并不好 - 如果某个字符有跨越两个块的字节表示怎么办?使用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)看看是否有区别.



1> Jon Skeet..:

我怀疑您的文件实际上并未编码为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");



2> Zach Scriven..:

将文件解析为固定大小的字节块并不好 - 如果某个字符有跨越两个块的字节表示怎么办?使用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)看看是否有区别.



3> McDowell..:

@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
?ô

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

UTF-
8ôÃ'

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

5554 462d 380a f4c3 b40a

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

推荐阅读
mobiledu2402851323
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有