Java-无法正确读取BufferedReader中的特殊字符

Java-无法正确读取BufferedReader中的特殊字符,java,bufferedreader,Java,Bufferedreader,我已经创建了从csv文件读取数据的代码。但是,我无法处理特殊字符,例如 例如,我的基本成本(K)被解读为我的基本成本(K) 我能做些什么来纠正这个问题 public void parseCSVFile(String filename){ try { br = new BufferedReader(new FileReader(csvDirectory + filename)); while ((parsedLines = br.rea

我已经创建了从csv文件读取数据的代码。但是,我无法处理特殊字符,例如

例如,
我的基本成本(K)
被解读为
我的基本成本(K)

我能做些什么来纠正这个问题

public void parseCSVFile(String filename){

     try {
            br = new BufferedReader(new FileReader(csvDirectory + filename));

            while ((parsedLines = br.readLine()) != null) {

                String[] parsedData = parsedLines.split(csvSplitByComma);

                entireFeed.add(parsedData[0]);
                entireFeed.add(parsedData[1]);

                System.out.println(parsedData[0]);
                System.out.println(parsedData[1]);

                it = entireFeed.iterator();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
}

似乎是编码问题。找出文件编码的字符集。假设编码是UTF-8,您可以这样做

new BufferedReader(new InputStreamReader(new FileInputStream("my/path/to/File"), "UTF-8"));

这将解决您的问题

编写CSV的代码已损坏。它用UTF-8对所写的文本进行了三重编码

在UTF-8中,ASCII字符(代码点0–127)表示为单个字节;它们不需要编码。这就是为什么只有<代码>受到影响

需要两个UTF-8字节。这些字节是:0xc2,0xa3。如果编写CSV文件的代码正确使用了UTF-8,则该字符将在文件中显示为这两个字节

但是,显然,某些代码在某处使用单字节字符集(如ISO-8859-1)读取文件,导致每个单独的字节被视为自己的字符。然后,它使用UTF-8对这些单独的字符进行编码。也就是说,它接受了{0xc2,0xa3}字节,并用UTF-8对它们进行编码。然后产生这些字节:0xc3、0x82、0xc2、0xa3。(特别是:U+00C2字符在UTF-8中表示为0xc3 0x82,U+00A3字符在UTF-8中表示为0xc2 0xa3。)

然后,在那之后的某个时候,同样的事情又发生了。这四个字节使用单字节字符集读取,每个字节被视为自己的字符,这四个字符中的每一个都用UTF-8编码,这导致了八个字节:0xc3、0x83、0xc2、0x82、0xc3、0x82、0xc2、0xa3。(当编码为UTF-8时,并不是每个字符都转换为两个字节;碰巧所有这些字符都是空的。)

这就是为什么使用ISO-8859-1字符集读取文件时,每个字节有一个字符:

à   ƒ      ‚   à   ‚      £
c3  83  c2  82  c3  82  c2  a3
(从技术上讲,
实际上是U+201A“一个低9引号”,但许多Windows字体在历史上每个字符有一个字节,该字符位于0x82位置。)

既然我们知道你的档案是怎么变成这样的,你怎么办

首先,不要让事情变得更糟。如果您可以控制编写文件的代码,请确保代码明确指定了用于读取和写入的字符集。UTF-8几乎总是最好的选择,至少对于任何使用西方字符为主的文件来说是这样

第二,如何修复文件?恐怕没有办法自动检测这种错误编码,但至少在这一个文件的情况下,您可以对其进行三重解码

如果文件不是很大,您可以将其全部读入内存:

byte[] bytes = Files.readAllBytes(Paths.get(csvDirectory, filename));
// First decoding: £ is represented as four characters
String content = new String(bytes, "UTF-8");

bytes = new byte[content.length()];
for (int i = content.length() - 1; i >= 0; i--) {
    bytes[i] = (byte) content.charAt(i);
}
// Second decoding: £ is represented as two characters
content = new String(bytes, "UTF-8");

bytes = new byte[content.length()];
for (int i = content.length() - 1; i >= 0; i--) {
    bytes[i] = (byte) content.charAt(i);
}
// Third decoding: £ is represented as one character
content = new String(bytes, "UTF-8");

br = new BufferedReader(new StringReader(content));

// ...
如果是一个大文件,您将希望以字节的形式读取每一行:

try (InputStream in = new BufferedInputStream(
    Files.newInputStream(Paths.get(csvDirectory, filename)))) {

    ByteBuffer lineBuffer = ByteBuffer.allocate(64 * 1024);

    int b = 0;
    while (b >= 0) {
        lineBuffer.clear();

        for (b = in.read();
             b >= 0 && b != '\n' && b != '\r';
             b = in.read()) {

            lineBuffer.put((byte) b);
        }

        if (b == '\r') {
            in.mark(1);
            if (in.read() != '\n') {
                in.reset();
            }
        }

        lineBuffer.flip();
        byte[] bytes = new byte[lineBuffer.limit()];
        lineBuffer.get(bytes);

        // First decoding: £ is represented as four characters
        String parsedLine = new String(bytes, "UTF-8");

        bytes = new byte[parsedLine.length()];
        for (int i = parsedLine.length() - 1; i >= 0; i--) {
            bytes[i] = (byte) parsedLine.charAt(i);
        }
        // Second decoding: £ is represented as two characters
        parsedLine = new String(bytes, "UTF-8");

        bytes = new byte[parsedLine.length()];
        for (int i = parsedLine.length() - 1; i >= 0; i--) {
            bytes[i] = (byte) parsedLine.charAt(i);
        }
        // Third decoding: £ is represented as one character
        parsedLine = new String(bytes, "UTF-8");

        // ...
    }
}

可能是@NiranjanKumar的副本我尝试了以下方法,但仍然没有成功。我得到了“我的基本成本(KÃÃÃbr)”:BufferedReader br=新的BufferedReader(新的InputStreamReader(新文件InputStream(文件),“ISO-8859-1”);可能是@AlexErohin的副本我已经尝试过了,但仍然得到了最初的错误。感谢你的解释,我的错误在哪里是有道理的。我已经纠正了我的代码,它现在正在按预期工作。