Код, который написал ваш CSV сломана. Это triple-encoded в 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 «Single Low-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");
// ...
}
}
Возможный дубликат http://stackoverflow.com/questions/9281629/read-special-characters-in-java-with-bufferedreader –
@NiranjanKumar Я пробовал следующее и все еще не работал. Я возвращаюсь «Моя базовая стоимость (KÃÃÂÂÃÃÂÂ)»: BufferedReader br = new BufferedReader ( новый InputStreamReader (новый FileInputStream (файл), «ISO-8859-1»)); – NSC
Возможный дубликат файла [Read/write .txt со специальными символами] (http://stackoverflow.com/questions/4597749/read-write-txt-file-with-special-characters) –