1. Sintomas de erros
Em um mundo ideal, os programadores sempre sabem em qual codificação o arquivo foi gravado e informam corretamente ao lê-lo. Mas a realidade — é um mundo onde os arquivos circulam entre Windows, Linux, servidores, editores, e cada um interpreta os bytes à sua maneira. Como resultado, encontramos sintomas como:
- “Mojibake” — em vez do texto esperado, vemos caracteres estranhos, pontos de interrogação, quadradinhos ou uma sequência de letras que não se parece com nenhum idioma do mundo.
- Perda de caracteres — parte do texto desaparece ou é substituída por ?.
- Exceções — por exemplo, MalformedInputException, quando o Java não consegue “digerir” os bytes na codificação escolhida.
- Erros de parsing — o programa não consegue processar corretamente o arquivo porque palavras-chave ou estruturas foram danificadas devido à distorção do texto.
Aqui está um exemplo clássico de “mojibake” ao ler um arquivo em cirílico com a codificação errada:
Esperado: Olá, mundo!
Obtido: Привет, мир
Isso não é um novo idioma, e sim o resultado de os bytes terem sido interpretados com o “dicionário” errado.
2. Por que ocorrem erros: a raiz do problema
O arquivo foi gravado em uma codificação e lido em outra
Suponha que alguém salvou o arquivo em Windows-1251, e você o abre em UTF-8. O Java tenta decodificar os bytes pelas regras de UTF-8, mas sai sem sentido, porque os valores dos bytes não correspondem ao esperado.
Uso da codificação do sistema “padrão”
Se você não informar a codificação explicitamente, o Java usa a do sistema — aquela que está configurada no seu computador. No Windows com localidade russa pode ser Windows-1251, no Linux — UTF-8, no Mac — também UTF-8. Um arquivo que abre perfeitamente para você pode ficar ilegível para um colega com outro SO.
Uso de construtores obsoletos
Em versões antigas do Java (e em alguns livros) aparecem com frequência construções com FileReader/FileWriter, que usam a codificação do sistema e não dão controle — isso é uma armadilha e fonte de “mojibake”.
FileReader reader = new FileReader("file.txt");
FileWriter writer = new FileWriter("file.txt");
Presença ou ausência de BOM (Byte Order Mark)
Algumas codificações (por exemplo, UTF-8 com BOM ou UTF-16) adicionam bytes especiais no início do arquivo para sinalizar sua natureza. Se o programa não espera BOM ou, ao contrário, espera e não encontra, podem surgir problemas: ou os primeiros caracteres do arquivo serão distorcidos, ou o arquivo não será reconhecido.
3. Como os erros se manifestam: análise na prática
Exemplo 1: Arquivo com cirílico, gravado em Windows-1251, lido como UTF-8
import java.nio.file.*;
import java.nio.charset.*;
public class EncodingDemo {
public static void main(String[] args) throws Exception {
Path path = Paths.get("russian.txt");
// Arquivo gravado em Windows-1251, lendo como UTF-8 — vai virar mojibake!
try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
System.out.println(reader.readLine());
}
}
}
Como resultado, em vez de “Olá, mundo!”, você verá um conjunto de símbolos estranhos.
Exemplo 2: Arquivo gravado em UTF-8, lido como ISO-8859-1
try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.ISO_8859_1)) {
System.out.println(reader.readLine());
}
Resultado: Todos os caracteres não ASCII serão corrompidos ou substituídos por ?.
Exemplo 3: Exceção ao ler o arquivo
Se os bytes não obedecem às regras da codificação escolhida, o Java pode lançar uma exceção:
Exception in thread "main" java.nio.charset.MalformedInputException: Input length = 1
at java.base/sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
...
Isso significa que o Java encontrou um byte que não pode ser interpretado corretamente na codificação selecionada.
4. Diagnóstico: como entender o que há de errado com a codificação
Verifique a codificação do arquivo
- Em editores como Notepad++, VS Code ou Sublime Text, normalmente é possível ver ou alterar a codificação do arquivo (geralmente na barra inferior).
- No Linux, com um comando você pode obter uma dica sobre a codificação (mas nem sempre com 100% de precisão):
file imya_fayla.txt
Verifique a codificação do sistema do Java
Imprima no console o valor da propriedade file.encoding:
System.out.println(System.getProperty("file.encoding"));
Use dados de teste
Crie um arquivo pequeno com diferentes caracteres (cirílicos, latinos, caracteres especiais, emoji), tente lê-lo com diferentes codificações e veja quando o resultado coincide com o esperado.
Sempre declare explicitamente a codificação
Assim que você vir no código leitura/gravação de arquivo sem codificação especificada — é motivo para ficar atento. Por exemplo, use Files.newBufferedReader(..., StandardCharsets.UTF_8) em vez de valores “padrão”.
5. Boas práticas: como não cair na armadilha
Regra nº 1:
SEMPRE informe explicitamente a codificação ao trabalhar com arquivos, especialmente se o arquivo for usado em computadores diferentes, em sistemas operacionais distintos ou enviado pela rede.
Regra nº 2:
Use codificações modernas e amplamente aceitas — em primeiro lugar UTF-8 (StandardCharsets.UTF_8). Só use outras codificações se houver exigências específicas (por exemplo, integração com um sistema legado).
Regra nº 3:
Evite as classes FileReader e FileWriter (elas não permitem informar a codificação); em vez delas, use InputStreamReader, OutputStreamWriter ou métodos de Files com Charset explícito.
Regra nº 4:
Verifique o resultado! Abra os arquivos gravados em editores com suporte a diferentes codificações para se certificar de que o texto está correto.
6. Particularidades e nuances: BOM, XML, JSON e outros casos “divertidos”
BOM (Byte Order Mark): às vezes um arquivo em UTF-8 começa com bytes “invisíveis” (EF BB BF). A maioria dos programas modernos os ignora, mas alguns podem mostrar “mojibake” no início da linha ou rejeitar o arquivo (por exemplo, parsers antigos de XML/JSON).
XML/HTML: às vezes, no início do arquivo há uma linha como <?xml version="1.0" encoding="UTF-8"?>. Ela informa ao programa qual codificação esperar. Mas se a codificação real não coincide com a declarada — novamente “mojibake”.
JSON: pelo padrão deve ser UTF-8, mas se o arquivo foi criado em Windows-1251, o parser emitirá erro ou dados distorcidos.
GO TO FULL VERSION