FreeToGenerate.com

Um arquivo .properties não tem codificação própria: quem decide é o carregador, e os dois carregadores discordam. Nada é enviado.

Experimente:

Você digita aqui como texto e a página codifica em UTF-8, que é o que qualquer editor atual salva. As duas colunas abaixo mostram o que cada um dos dois carregadores do Java leria desses mesmos bytes.

O que cada carregador lê

Os dois carregadores divergem. O arquivo está salvo em UTF-8 e load(InputStream) lê um caractere por byte, então tudo que não é ASCII chega como dois ou três caracteres em vez de um.

Chaveload(InputStream), ISO 8859-1load(Reader), UTF-8
greetingdivergemcafécafé
farewelldivergemadiósadiós
ascii.onlythis line is fine either waythis line is fine either way

Os mesmos bytes, decodificados de duas formas. As linhas marcadas são aquelas em que os dois divergem: ali seu programa verá um valor diferente conforme o arquivo tenha sido aberto.

Vale saber

Nada a relatar.

A forma que independe do carregador

Tudo que não é ASCII escrito como escape, de modo que os dois carregadores leem exatamente a mesma coisa. É o que store(OutputStream) produz e a única forma que não se quebra quando um editor troca a codificação do arquivo.

Resumo

Entradas
3
Chaves em que divergem
2

Tudo roda no seu navegador. Nada do que você colar é enviado a lugar nenhum.

Também disponível em: English · Español · Français · العربية

Arquivo .properties do Java: acentos, escapes e codificação

Cole um arquivo .properties e compare o que cada carregador do Java lê dos mesmos bytes, junto com a forma escapada que faz os dois concordarem.

O que é um arquivo .properties

O arquivo .properties é o formato de configuração mais antigo e mais simples do Java: uma chave e um valor por linha, separados por um sinal de igual, e uma cerquilha para os comentários. Está na biblioteca padrão desde o começo, ainda é o formato da maioria dos pacotes de tradução e é simples o bastante para qualquer um editar no programa que estiver aberto.

Essa simplicidade esconde uma coisa. Um arquivo .properties não tem codificação própria. Nada dentro do arquivo diz qual é, não há cabeçalho nem marca de ordem de bytes, e a resposta depende inteiramente do método que o abriu. Lido pelo método de fluxo, cada byte vira um caractere, ou seja, ISO 8859-1. Lido pelo método de leitor, a codificação é aquela com que o leitor foi construído. E a variante XML do mesmo formato assume UTF-8 por padrão. Um formato só, três respostas.

Por isso o arquivo que parece certo no seu editor não é necessariamente o arquivo que o seu programa lê. Esta página mostra as duas leituras dos mesmos bytes, marca os valores em que elas divergem e entrega a forma escapada que os dois carregadores leem igual.

Como usar

  1. Cole o arquivo. Ele é codificado em UTF-8, que é o que um editor atual salva. Os botões de exemplo cobrem texto acentuado, esse mesmo texto já escapado, as regras de separadores e comentários, um caminho do Windows e uma linha continuada.
  2. Compare as duas colunas. Uma é o que o carregador de fluxo lê e outra o que um leitor UTF-8 lê, ambas a partir dos mesmos bytes. Uma linha marcada é um valor que o seu programa verá diferente conforme o arquivo tenha sido aberto.
  3. Fique com a forma escapada. Tudo que não é ASCII escrito como escape. Essa versão não quebra quando um editor troca a codificação do arquivo, e é o que o próprio Java escreve ao salvar um .properties.

Por que o mesmo arquivo é lido de duas formas

A documentação diz sem rodeios: os métodos de fluxo funcionam como os de leitor, exceto que o fluxo está codificado em ISO 8859-1 e cada byte é um caractere Latin-1. A implementação é ainda mais direta: um byte vira caractere pela máscara dos seus oito bits baixos, sem nenhum decodificador no meio.

Assim, um arquivo salvo em UTF-8 e lido pelo método de fluxo dá um caractere por byte. Um e com acento agudo ocupa dois bytes em UTF-8, e esses dois bytes viram dois caracteres: é por isso que café chega como café. O valor não se corrompe no caminho e ninguém avisa; ele apenas é decodificado por uma regra em que quem salvou o arquivo não estava pensando.

Há aqui uma distinção que vale precisar, porque é fácil entendê-la ao contrário. Uma letra latina acentuada é perfeitamente representável em ISO 8859-1: o e acentuado é um único byte lá. O problema não é o caractere não poder ser escrito, é o arquivo ter sido escrito numa codificação diferente daquela com que está sendo lido. Um caractere acima de U+00FF é outro caso: esse não pode ser escrito em ISO 8859-1 de jeito nenhum e precisa ser escapado para o carregador de fluxo enxergá-lo, seja qual for a codificação do arquivo.

O escape que resolve os dois casos é uma barra invertida, a letra u e quatro dígitos hexadecimais. Quatro exatamente, e um único u: é o que diz a documentação, e a implementação de referência lança uma exceção em vez de adivinhar se encontrar outra coisa. O detalhe tem certa graça, porque a própria linguagem Java aceita qualquer número de letras u num escape dentro do código-fonte. A mesma sintaxe, duas regras diferentes, numa plataforma só.

As regras de escape que comem os seus dados

Depois de uma barra invertida, só quatro letras significam alguma coisa: t, r, n e f, para tabulação, retorno de carro, quebra de linha e avanço de página. Qualquer outro caractere depois da barra é ele mesmo, e a barra desaparece. Isso é deliberado, porque é assim que se coloca um dois-pontos ou um igual literal dentro de uma chave, mas transforma caminhos do Windows numa armadilha.

Escreva um caminho como C, dois-pontos, barra invertida, Users, barra invertida, temp, e o resultado é pior do que perder os separadores. A primeira barra some antes do U, e a segunda vem seguida de um t, então vira um caractere de tabulação. O que o seu programa recebe é C, dois-pontos, Users, uma tabulação invisível e depois emp. Dobrar cada barra invertida é a correção, e explica por que arquivos .properties cheios de caminhos do Windows têm aquela aparência estranha.

As regras de linha têm as próprias surpresas. Uma chave termina no primeiro igual, dois-pontos, espaço, tabulação ou avanço de página, o que vier antes, de modo que uma linha dizendo chave valor sem pontuação alguma é uma entrada perfeitamente válida. Os espaços iniciais são removidos de toda linha, tanto a cerquilha quanto o ponto de exclamação abrem um comentário, e uma linha terminada em barra invertida continua na seguinte, cujos espaços iniciais também são removidos. Essa última regra é o que permite quebrar uma mensagem longa e indentá-la sem que a indentação vire parte do valor.

O que esta ferramenta não faz

Ela não decide o que o seu arquivo contém de fato em disco. Aqui você está digitando texto, e a página codifica em UTF-8 porque é o que os editores salvam hoje. Se o seu arquivo estiver mesmo salvo em ISO 8859-1, o carregador de fluxo o lê corretamente e é ao leitor que é preciso avisar: a mesma comparação, ao contrário.

Ela para no formato. Se um valor é uma URL de banco razoável, se uma chave pertence a este pacote, se o mecanismo de resource bundles vai sequer achar o arquivo — nada disso aparece nos bytes nem é verificado. E se o que você tem é texto que já chegou corrompido, a ferramenta de reparo de mojibake deste site é a página certa; esta trata de produzir um arquivo que não possa se corromper.

O comportamento descrito é o do Java. Outras linguagens leem o mesmo formato com regras próprias e várias assumem UTF-8 direto, que é exatamente a razão de um arquivo funcionar numa cadeia de ferramentas e quebrar em outra. A forma escapada é o terreno comum: é ASCII puro, então todos os leitores concordam sobre ela.

Por que é grátis?

Codificar um texto e relê-lo de duas maneiras é aritmética que o seu navegador faz na hora. Não há servidor no caminho, então não há nada a medir nem conta a criar.

Nada é enviado. O arquivo que você cola fica nesta aba.