2016-11-16 6 views
0

Я создал код для чтения данных из файла csv. Однако я не могу обрабатывать специальные символы, такие как £.Java - Не удается прочитать специальные символы правильно в BufferedReader

Например, My Base Cost (K£) рассматривается как My Base Cost (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(); 
     } 
} 
+2

Возможный дубликат http://stackoverflow.com/questions/9281629/read-special-characters-in-java-with-bufferedreader –

+0

@NiranjanKumar Я пробовал следующее и все еще не работал. Я возвращаюсь «Моя базовая стоимость (KÃÃÂÂÃÃÂÂ)»: BufferedReader br = new BufferedReader ( новый InputStreamReader (новый FileInputStream (файл), «ISO-8859-1»)); – NSC

+0

Возможный дубликат файла [Read/write .txt со специальными символами] (http://stackoverflow.com/questions/4597749/read-write-txt-file-with-special-characters) –

ответ

2

Код, который написал ваш 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"); 

     // ... 
    } 
} 
+0

спасибо за объяснение, имеет смысл, где я ошибся. Я исправил свой код, и теперь он работает так, как ожидалось. – NSC

2

Кажется, проблема с кодировкой. Узнайте кодировку, в которой закодирован ваш файл. Предполагается, что кодирование в UTF-8 вы можете сделать что-то вроде этого

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

Это должно решить вашу проблему