将文本文件的内容读取到String时无效的字符

时间:2014-07-22 10:21:42

标签: java string file encoding

这是我的代码:

    StringBuffer fileData = new StringBuffer(1000);
    BufferedReader reader = new BufferedReader(new FileReader(file));
    char[] buf = new char[5000];
    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();

当我在Windows中运行时,一切都很好。

但是当我在字符串的开头用UNIX运行时,我看到了:

  



可能是什么问题?

2 个答案:

答案 0 :(得分:3)

给定char序列的hexdump可能是ef bb bf。我可能会说,因为我不得不猜测你的显示编码。

如果这是正确的,您尝试将ISO-8859-X读作UTF-8编码文件with BOM prefix。这与使用vi / vim打开文件时看不到这些字符的事实是一致的。大多数(如果不是全部)支持UTF-8的文本编辑器都知道如何处理BOM。

从Java开始,您必须手动跳过它(不知道它为什么在Windows上运行)。 另一种选择是将文本文件保存为UTF-8 而不用 BOM。

这已经讨论过了。例如见:



由于这不是很清楚,我做了以下实验:我创建了两个文件, utf-8 编码并包含字符串“L'élèvevaàl 'école。“这两个测试文件之间的唯一区别是一个有BOM前缀。

然后,根据OP提供的代码和Thomas Mueller的建议,我编写了一个非常简单的Java应用程序来使用各种编码来读取这些文件。这是代码:

public class EncodingTest {
    public static String read(String file, String encoding) throws IOException {
        StringBuffer fileData = new StringBuffer(1000);

        /* Only difference with OP code */
        /* I use *explicit* encoding while reading the file */
        BufferedReader reader = new BufferedReader(
                new InputStreamReader(new FileInputStream(file), encoding)
                );

        char[] buf = new char[5000];
        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();     
    }

    public static void main(String[] args) throws IOException {
        System.out.print(read("UTF-8-BOM-FILE", "UTF-8"));
        System.out.print(read("UTF-8-FILE", "UTF-8"));
        System.out.print(read("UTF-8-BOM-FILE", "ISO-8859-15"));
        System.out.print(read("UTF-8-FILE", "ISO-8859-15"));
    }
}

当我在Linux系统上运行此控制台编码为UTF8时,我得到以下结果:

$ java -cp bin EncodingTest
L'élève va à l'école.
L'élève va à l'école.
L'élÚve va à l'école.
L'élÚve va à l'école.

注意第三行是如何以与OP 给出的完全相同的顺序开始的。那是在读取 utf8编码文件时将BOM作为iso-8859-15

令人惊讶的是,前两行似乎是相同的,就像Java神奇地删除了BOM一样。我想这就是在Windows上附加OP的内容。

但仔细观察后发现:

$ java -cp bin EncodingTest | hexdump -C
00000000  ef bb bf 4c 27 c3 a9 6c  c3 a8 76 65 20 76 61 20  |...L'..l..ve va |
00000010  c3 a0 20 6c 27 c3 a9 63  6f 6c 65 2e 0a 4c 27 c3  |.. l'..cole..L'.|
00000020  a9 6c c3 a8 76 65 20 76  61 20 c3 a0 20 6c 27 c3  |.l..ve va .. l'.|
00000030  a9 63 6f 6c 65 2e 0a c3  af c2 bb c2 bf 4c 27 c3  |.cole........L'.|
00000040  83 c2 a9 6c c3 83 c5 a1  76 65 20 76 61 20 c3 83  |...l....ve va ..|
00000050  c2 a0 20 6c 27 c3 83 c2  a9 63 6f 6c 65 2e 0a 4c  |.. l'....cole..L|
00000060  27 c3 83 c2 a9 6c c3 83  c5 a1 76 65 20 76 61 20  |'....l....ve va |
00000070  c3 83 c2 a0 20 6c 27 c3  83 c2 a9 63 6f 6c 65 2e  |.... l'....cole.|
00000080  0a                                                |.|
00000081

请注意前三个字节:BOM已发送到输出 - 但我的控制台以某种方式丢弃了它们。但是,从Java程序的角度来看,那些存在的字节 - 我应该可以手动处理它们。


那么,这一切的道德是什么? OP确实存在两个问题:BOM前缀为UTF8编码文件。该文件读作iso-8859-X。

Yuris,为了解决这个问题,您必须在Java程序中明确使用正确的编码,要么丢弃前3个字节更改您的数据文件以删除BOM。

答案 1 :(得分:0)

byte[] content = Files.readAllBytes(file.toPath());
String s = new String(bytes, StandardCharsets.UTF_8);
s = s.replaceFirst("^\uFEFF", ""); // Remove starting BOM
return s;

BOM是一个字节顺序标记,可选地用作第一个char,零宽度空间,用于将文件标记为UTF-8(或UTF-16LE,UTF-16BE)。

它的主要用途似乎是在Windows上用于NotePad而不是将文本与ANSI编码混淆。

FileReader是一个无法设置编码的实用程序类。

可能是您的文件已经遭遇了错误的编码转换。也许UTF-8文本被粘贴到ANSI单字节编码文本中,或者其他任何内容。