Como converter seqüências de caracteres de e para matrizes de bytes UTF8 em Java


239

Em Java, eu tenho uma String e quero codificá-la como uma matriz de bytes (em UTF8 ou alguma outra codificação). Como alternativa, tenho uma matriz de bytes (em alguma codificação conhecida) e desejo convertê-la em uma String Java. Como faço essas conversões?

Respostas:


355

Converter de String em byte []:

String s = "some text here";
byte[] b = s.getBytes(StandardCharsets.UTF_8);

Converter de byte [] em String:

byte[] b = {(byte) 99, (byte)97, (byte)116};
String s = new String(b, StandardCharsets.US_ASCII);

Obviamente, você deve usar o nome de codificação correto. Meus exemplos usaram US-ASCII e UTF-8, as duas codificações mais comuns.


30
Atualmente, o US-ASCII não é uma codificação muito comum. Windows-1252 e ISO-8859-1 (que são superconjuntos de ASCII) são muito mais difundidos.
227 Michael Borgwardt

11
Na verdade, acho isso bastante comum no meu trabalho. Frequentemente leio fluxos de bytes que podem ter sido salvos como Windows-1252 ou ISO-8859-1 ou mesmo apenas como "saída do programa herdado que tivemos nos últimos 10 anos", mas que contêm bytes com garantia de validade Caracteres US-ASCII. Também tenho muitas vezes a necessidade de GERAR esses arquivos (para consumo por código que pode ou não ser capaz de lidar com caracteres não-ASCII. Basicamente, o US-ASCII é o "maior denominador comum" de muitos softwares.
Mcherm 13/10/09

1
Esse método, no entanto, não relatará nenhum problema na conversão. Pode ser o que você deseja. Caso contrário, é recomendável usar o CharsetEncoder.
Michael Piefel

7
@Pacerier porque os documentos para Charset listam "UTF-8" como um dos conjuntos de caracteres padrão. Acredito que sua ortografia também seja aceita, mas fui com o que os documentos disseram.
Mckm

20
Desde o JDK7, você pode usar o StandardCharsets.UTF_8 docs.oracle.com/javase/7/docs/api/java/nio/charset/…
Rafael Membrives

95

Aqui está uma solução que evita realizar a pesquisa Charset para cada conversão:

import java.nio.charset.Charset;

private final Charset UTF8_CHARSET = Charset.forName("UTF-8");

String decodeUTF8(byte[] bytes) {
    return new String(bytes, UTF8_CHARSET);
}

byte[] encodeUTF8(String string) {
    return string.getBytes(UTF8_CHARSET);
}

4
@mcherm: Mesmo que a diferença de desempenho seja pequena, prefiro usar objetos (Charset, URL, etc.) sobre suas formas de string, quando possível.
Bart van Heukelom

7
Nota: "Desde 1.6" String pública (bytes [] bytes, Charset charset)
leo

1
Em relação a "evita realizar a pesquisa Charset para todas as conversões" ... cite alguma fonte. O java.nio.charset.Charset não é criado sobre String.getBytes e, portanto, possui mais sobrecarga que String.getBytes?
21712 Pacerier

2
Os documentos afirmam: "O comportamento desse método quando essa cadeia não pode ser codificada no conjunto de caracteres especificado não é especificado. A classe CharsetEncoder deve ser usada quando for necessário mais controle sobre o processo de codificação."
paiego 19/10/2013

24
Nota: desde o Java 1.7, é possível usar StandardCharsets.UTF_8para uma maneira constante de acessar o conjunto de caracteres UTF-8.
Kat

17
String original = "hello world";
byte[] utf8Bytes = original.getBytes("UTF-8");

Obrigado! Eu escrevi novamente adicionando a outra direção da conversão.
mcherm

1
@smink O traço não é opcional. Isso deve usar "UTF-8"
Mel Nicholson

14

Você pode converter diretamente por meio do construtor String (byte [], String) e do método getBytes (String). Java expõe conjuntos de caracteres disponíveis por meio da classe Charset . A documentação do JDK lista as codificações suportadas .

90% do tempo, essas conversões são realizadas em fluxos, portanto, você usaria as classes Reader / Writer . Você não decodificaria incrementalmente usando os métodos String em fluxos de bytes arbitrários - se deixaria aberto a erros que envolvem caracteres multibyte.


Você pode elaborar? Se meu aplicativo codifica e decodifica Strings UTF-8, qual é a preocupação com caracteres multibytes?
raffian

@raffian Podem ocorrer problemas se você não transformar todos os dados de caracteres de uma só vez. Veja aqui um exemplo.
McDowell

12

Minha implementação do tomcat7 está aceitando strings como ISO-8859-1; apesar do tipo de conteúdo da solicitação HTTP. A solução a seguir funcionou para mim ao tentar interpretar corretamente caracteres como 'é'.

byte[] b1 = szP1.getBytes("ISO-8859-1");
System.out.println(b1.toString());

String szUT8 = new String(b1, "UTF-8");
System.out.println(szUT8);

Ao tentar interpretar a sequência como US-ASCII, as informações do byte não foram interpretadas corretamente.

b1 = szP1.getBytes("US-ASCII");
System.out.println(b1.toString());

8
Para sua informação, a partir do Java 7, você pode usar constantes para nomes de conjuntos de caracteres como StandardCharSets.UTF_8e StandardCharSets.ISO_8859_1.
Basil Bourque

Salvei meu dia, trabalhando absolutamente bem para a primeira solução mencionada acima.
Hassan Jamil

7

Como alternativa, o StringUtils do Apache Commons pode ser usado.

 byte[] bytes = {(byte) 1};
 String convertedString = StringUtils.newStringUtf8(bytes);

ou

 String myString = "example";
 byte[] convertedBytes = StringUtils.getBytesUtf8(myString);

Se você possui um conjunto de caracteres não padrão, pode usar getBytesUnchecked () ou newString () de acordo.


4
Observe que este StringUtils do Commons Codec , não o Commons Lang.
Arend v. Reinersdorff

Sim, um pouco de pegadinha! Para Gradle, os usuários do Maven: "commons-codec: commons-codec: 1.10" (no momento da redação). Isso também é fornecido como uma dependência do Apache POI, por exemplo. Além do Apache Commons para o resgate, como sempre!
mike roedor

2

Para decodificar uma série de bytes em uma mensagem de string normal, finalmente consegui trabalhar com a codificação UTF-8 com este código:

/* Convert a list of UTF-8 numbers to a normal String
 * Usefull for decoding a jms message that is delivered as a sequence of bytes instead of plain text
 */
public String convertUtf8NumbersToString(String[] numbers){
    int length = numbers.length;
    byte[] data = new byte[length];

    for(int i = 0; i< length; i++){
        data[i] = Byte.parseByte(numbers[i]);
    }
    return new String(data, Charset.forName("UTF-8"));
}

1

Se você estiver usando ASCII de 7 bits ou ISO-8859-1 (um formato surpreendentemente comum), não precisará criar um novo java.lang.String . É muito mais eficiente simplesmente converter o byte em char:

Exemplo de trabalho completo:

for (byte b : new byte[] { 43, 45, (byte) 215, (byte) 247 }) {
    char c = (char) b;
    System.out.print(c);
}

Se você não estiver usando caracteres estendidos como Ä, Æ, Å, Ç, Ï, Ê e pode ter certeza de que os únicos valores transmitidos são dos primeiros 128 caracteres Unicode, esse código também funcionará para UTF-8 e ASCII estendido. (como cp-1252).


1

Não posso comentar, mas não quero iniciar um novo tópico. Mas isso não está funcionando. Uma simples ida e volta:

byte[] b = new byte[]{ 0, 0, 0, -127 };  // 0x00000081
String s = new String(b,StandardCharsets.UTF_8); // UTF8 = 0x0000, 0x0000,  0x0000, 0xfffd
b = s.getBytes(StandardCharsets.UTF_8); // [0, 0, 0, -17, -65, -67] 0x000000efbfbd != 0x00000081

Eu precisaria da mesma matriz antes e depois da codificação que não é (isso se refere à primeira resposta).


0
//query is your json   

 DefaultHttpClient httpClient = new DefaultHttpClient();
 HttpPost postRequest = new HttpPost("http://my.site/test/v1/product/search?qy=");

 StringEntity input = new StringEntity(query, "UTF-8");
 input.setContentType("application/json");
 postRequest.setEntity(input);   
 HttpResponse response=response = httpClient.execute(postRequest);

A Entidade de String converte 'query' em utf-8 ou apenas se lembra quando anexa a entidade?
SyntaxRules

0
Charset UTF8_CHARSET = Charset.forName("UTF-8");
String strISO = "{\"name\":\"א\"}";
System.out.println(strISO);
byte[] b = strISO.getBytes();
for (byte c: b) {
    System.out.print("[" + c + "]");
}
String str = new String(b, UTF8_CHARSET);
System.out.println(str);

0
Reader reader = new BufferedReader(
    new InputStreamReader(
        new ByteArrayInputStream(
            string.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8));

-9

terrivelmente tarde, mas eu apenas encontrei esse problema e esta é a minha correção:

private static String removeNonUtf8CompliantCharacters( final String inString ) {
    if (null == inString ) return null;
    byte[] byteArr = inString.getBytes();
    for ( int i=0; i < byteArr.length; i++ ) {
        byte ch= byteArr[i]; 
        // remove any characters outside the valid UTF-8 range as well as all control characters
        // except tabs and new lines
        if ( !( (ch > 31 && ch < 253 ) || ch == '\t' || ch == '\n' || ch == '\r') ) {
            byteArr[i]=' ';
        }
    }
    return new String( byteArr );
}

2
Primeiro, não é uma conversão: é a remoção de bytes não imprimíveis. Segundo, pressupõe que a codificação padrão do SO subjacente seja realmente baseada em ASCII para caracteres imprimíveis (não funcionará nos mainframes IBM usando EBCDIC, por exemplo).
21413 Isaac
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.