Se é um arquivo UTF-8

Pessoal, estou começando a fazer um programa que transforma a codificação de arquivos em UTF-8. Como posso saber se um arquivo está em formato UTF-8 pelo código Java?

vlews

É mais complicado que parece.
a) Pode ser que ele comece pelos seguintes 3 bytes:
EF BB BF
Se ele começar com esses 3 bytes (BOM = Byte Order Marker), é com certeza um arquivo UTF-8.
b) Pode ser que ele não comece com esses bytes. Portanto, para saber se é UTF-8 mesmo, você pode fazer uma de duas coisas:

  • Ou você tenta adivinhar, basicamente procurando se há sequências com o byte C3, seguido de outro caracter. Exemplo:

Texto original:

Áurea Évora Ícaro Óbolo Única Ânfora Ênfase Ônfalo

Codificação em UTF-8:

0000    EF BB BF C3 81 75 72 65  61 20 C3 89 76 6F 72 61   ∩....urea ..vora
0010    20 C3 8D 63 61 72 6F 20  C3 93 62 6F 6C 6F 20 C3    ..caro ..bolo .
0020    9A 6E 69 63 61 20 C3 82  6E 66 6F 72 61 20 C3 8A   .nica ..nfora ..
0030    6E 66 61 73 65 20 C3 94  6E 66 61 6C 6F 0D 0A      nfase ..nfalo..

Codificação em ISO-8859-1 ou Windows-1252 (o próprio Windows chama de “ANSI” embora não seja exatamente ANSI):

0000    C1 75 72 65 61 20 C9 76  6F 72 61 20 CD 63 61 72   .urea .vora .car
0010    6F 20 D3 62 6F 6C 6F 20  DA 6E 69 63 61 20 C2 6E   o .bolo .nica .n
0020    66 6F 72 61 20 CA 6E 66  61 73 65 20 D4 6E 66 61   fora .nfase .nfa
0030    6C 6F 0D 0A                                        lo..

Uma forma boboca é "forçar a barra", ou seja, tentar efetuar a codificação e ver se o Java lança alguma exceção.
Algo como:

byte[] bytes = ...;
String s = null;
if (bytes.length &gt 3 && bytes[0] == (byte) 0xEF && bytes[1] == (byte) 0xBB && bytes[2] == (byte) 0xBF) {
    ... é UTF-8
} else {
try {
    s = new String (bytes, "UTF-8"); // tentar primeiro para ver se é UTF-8
} catch (Exception ex) {
    try { 
        s = new String (bytes, "ISO-8859-1"); // deu pau com UTF-8, deve ser ISO-8859-1
    } catch (Exception ex) {
        // tente outras codificações se você sabe que pode ser outra.
    }
}

Valew, thingol… é mais difícil do que parece mesmo, vou fazer alguns testes… :wink:

Idependente da detecção, alguém sabe como posso fazer a conversão?

Bom fiz um teste pegando um arquivo que tem acentos, tipo “ááéééé”, peguei o conteúdo desse arquivo em uma String:

String conteudo = ...; Writer writer = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(path)) ); writer.write(new String(conteudo.getBytes(), "UTF-8")); writer.flush(); writer.close(); Mas quando vou verificar o que ele escreveu ficaram umonte de ???

Que será?

[quote=andre_guitar7]Bom fiz um teste pegando um arquivo que tem acentos, tipo “ááéééé”, peguei o conteúdo desse arquivo em uma String:

String conteudo = ...; Writer writer = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(path)) ); writer.write(new String(conteudo.getBytes(), "UTF-8")); writer.flush(); writer.close(); Mas quando vou verificar o que ele escreveu ficaram umonte de ???

Que será?[/quote]

Bom, não sei qual a codificação padrão usada pelo seu Java. Então você precisa explicitá-la. Por exemplo:

String conteudo = ...; Writer writer = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(path), "UTF-8") ); writer.write(new String(conteudo.getBytes(), "UTF-8")); writer.flush(); writer.close(); Mas quando vou verificar o que ele escreveu ficaram umonte de ???

[quote=thingol]Mas quando vou verificar o que ele escreveu ficaram umonte de ???
[/quote]
No lugar dos acentos ficaram pontos de interrogação (???)

Fiz o teste da forma que vc colocou, agora no lugar dos caracteres com acentos ficaram outros caracteres diferentes, ficou bem maluco…

Provavelmente você está usando o Notepad ou outro editor, e está tentando visualizar em ANSI (ISO-8859-1). Aí é que você vai visualizar “Áurea” como
?çurea ou coisa parecida.

Não, está aparecendo i com dois pontos em cima, ponto de interrogação de ponta cabeça e o símbolo de 1/2, nessa sequencia, repetido a cada caractere com acento. Quando vou visualizar este arquivo no IE aparece quadradinhos em qquer tipo de codificação setada manualmente no browser… será que não é a forma que estou lendo o arquivo?

[code] BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream(path))
);
String linha;
String conteudo = “”;

while((linha = reader.readLine()) != null){
conteudo += linha + “\n”;
}

reader.close();[/code] O resto vc já sabe…

E se eu fosse ler caractere a caractere da minha String… poderia converter os caracteres com acento para UTF-8?

Acho que você precisa analisr o arquivo original.

thingol, vc tinha razão… o Eclipse estava lendo o arquivo na codificação Cp1252, por isso ficara aqueles caracteres esquisitos quando tinha acentos, era só mudar a forma de ele ler aquele arquivo e pronto… bom, meu problema agora é validar pelo código quando um arquivo é UTF-8 ou não… essa condição:

byte[] bytes = ...; String s = null; if (bytes.length > 3 && bytes[0] == (byte) 0xEF && bytes[1] == (byte) 0xBB && bytes[2] == (byte) 0xBF) { ... é UTF-8 } else { try { s = new String (bytes, "UTF-8"); // tentar primeiro para ver se é UTF-8 } catch (Exception ex) { try { s = new String (bytes, "ISO-8859-1"); // deu pau com UTF-8, deve ser ISO-8859-1 } catch (Exception ex) { // tente outras codificações se você sabe que pode ser outra. } } que vc colocou, não deu certo…

thingol, que vc acha… se eu tenho um arquivo em UTF-8 e converto, em Java, para ISO-8859-1, todos os caracteres com acento ficam Ã. É só transformar de UTF-8 para ISO e usar o contais(“Ô).

conteudo = new String(texto.getBytes("ISO-8859-1")); if(conteudo.contains("Ã")){ //é UTF-8 }else{ //não é } muito escroto?