Java App: Não é possível ler arquivo codificado iso-8859-1 corretamente

votos
6

I tem um arquivo que é codificado como iso-8859-1, e contém caracteres, tal como O.

Estou lendo este arquivo com código java, algo como:

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);
}

No entanto, o caráter ô é sempre truncado, geralmente imprimir como um? .

Eu li em torno do assunto (e aprendeu um pouco sobre a maneira) eg

mas ainda não pode começar este trabalho

Curiosamente isso funciona no meu pc local (xp), mas não na minha caixa de linux.

Eu verifiquei que o meu jdk suporta os conjuntos de caracteres necessários (eles são padrão, então isso é nenhuma surpresa) usando:

System.out.println(java.nio.charset.Charset.availableCharsets());
Publicado 31/01/2009 em 11:51
fonte usuário
Em outras línguas...                            


5 respostas

votos
3

Se você puder, tente executar o programa no depurador para ver o que está dentro corda seu 's' depois que ele for criado. É possível que ele tem conteúdo correto, mas a saída é ilegível após System.out.println (s) chamada. Nesse caso, provavelmente há incompatibilidade entre o que Java pensa é a codificação de sua saída e codificação de caracteres de seu terminal / console no Linux.

Respondeu 31/01/2009 em 11:59
fonte usuário

votos
12

Eu suspeito que seja o seu arquivo não está realmente codificado como ISO-8859-1, ou não System.out não sabe como imprimir o personagem.

Eu recomendo que para verificar se o primeiro, você examinar o byte relevante no arquivo. Para verificar se o segundo, examinar o caráter relevante na cadeia, imprimi-lo para fora com

 System.out.println((int) s.getCharAt(index));

Em ambos os casos, o resultado deve ser 244 decimal; Hex 0xF4.

Veja meu artigo sobre Unicode depuração para o conselho geral (o código apresentado é em C #, mas é fácil de converter para Java, e os princípios são os mesmos).

Em geral, a propósito, eu embrulhar o fluxo com uma InputStreamReadercom a codificação correta - é mais fácil do que criar novas cordas "à mão". Sei que isso pode ser apenas código de demonstração embora.

EDIT: Aqui está uma maneira muito fácil de provar ou não o console vai funcionar:

 System.out.println("Here's the character: \u00f4");
Respondeu 31/01/2009 em 11:59
fonte usuário

votos
9

Analisar o arquivo como blocos de tamanho fixo de bytes não é bom --- o que se algum personagem tem uma representação byte que atravessa em dois blocos? Use um InputStreamReadercom a codificação de caracteres apropriada em vez disso:

 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);
 }

Btw, lembre-se de verificar se o caractere Unicode pode realmente ser exibido corretamente. Você também pode redirecionar a saída do programa para um arquivo e, em seguida, compará-lo com o arquivo original.

Como Jon Skeet sugere, o problema também pode ser consola-relacionado. Experimente System.console().printf(s)para ver se há uma diferença.

Respondeu 31/01/2009 em 12:18
fonte usuário

votos
1

Basicamente, se ele funciona em seu PC local XP, mas não no Linux, e você estiver analisando o mesmo arquivo exato (ou seja, você transferiu de forma binária entre as casas), em seguida, ele provavelmente tem algo a ver com o System.out. chamada println. Eu não sei como você verificar a saída, mas se você fazê-lo através da ligação com um shell remoto da caixa de XP, então não é o conjunto de caracteres do shell (eo cliente) a considerar.

Além disso, o que Zach Scrivena sugere também é verdadeiro - você não pode assumir que você pode criar seqüências de blocos de dados dessa forma - ou usar um InputStreamReader ou ler os dados completos em uma matriz primeiro (obviamente, não vai trabalhar para um grande arquivo) . No entanto, uma vez que parece funcionar no XP, então eu arriscaria que isso provavelmente não é o seu problema, neste caso específico.

Respondeu 31/01/2009 em 12:36
fonte usuário

votos
6

@ Joel - a sua própria resposta confirma que o problema é a diferença entre a codificação padrão do seu sistema operacional (UTF-8, o Java pegou) ea codificação seu terminal está usando (ISO-8859-1).

Considere este código:

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);
}

Por padrão, o meu Ubuntu (8,04) Terminal usa a codificação UTF-8. Com esta codificação, isto é impresso:

UTF-8
? Ô

Se alterno codificação do terminal com a norma ISO 8859-1, este é impresso:

UTF-8
ôÃ'

Em ambos os casos, os mesmos bytes estão sendo emitidos pelo programa Java:

5554 462d 380a f4c3 b40a

A única diferença está na forma como o terminal está a interpretar os bytes recebidos. Na norma ISO 8859-1, ô é codificado como 0xF4. Em UTF-8, ô é codificado como 0xC3B4. Os outros personagens são comuns a ambas as codificações.

Respondeu 31/01/2009 em 16:40
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more