Bytes de uma string em Java

179

Em Java, se eu tiver uma String x, como posso calcular o número de bytes nessa string?

Verde
fonte
15
Pode-se usar uma String para representar o corpo de uma resposta HTTP e usar o tamanho para definir o cabeçalho "Content-Length", especificado em octetos / bytes, não em caracteres. w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13
iX3
4
Uma coluna do banco de dados pode ter restrição de comprimento em bytes, por exemplo, VARCHAR2 (4000 BYTE) no Oracle. Pode-se querer saber a contagem de bytes de uma String na codificação desejada para saber se a String seria adequada.
Somu
@ iX3 Exatamente o mesmo que eu estava tentando fazer.
MC Emperor
1
Acredito que existem duas interpretações possíveis para essa pergunta, dependendo da intenção: uma é "quanta memória minha String usa?". A resposta é fornecida por @roozbeh abaixo (talvez sutilezas do módulo VM como OOPS compactado). A outra é "se eu converter a string em um byte [] quanta memória essa matriz de bytes usaria?". Esta é a pergunta que é respondida por Andrzej Doyle. A diferença pode ser grande: "Hello World" em UTF8 é de 11 bytes, mas a String (por @roozbeh) é de 50 bytes (se minha matemática estiver correta).
Blanc L.
Eu deveria ter acrescentado que os 11 bytes não incluem a sobrecarga do objeto byte [] que os contém, portanto a comparação é um pouco enganadora.
L. Blanc

Respostas:

289

Uma string é uma lista de caracteres (ou seja, pontos de código). O número de bytes utilizados para representar a sequência depende inteiramente da codificação usada para transformá-la em bytes .

Dito isso, você pode transformar a string em uma matriz de bytes e, em seguida, analisar seu tamanho da seguinte maneira:

// The input string for this test
final String string = "Hello World";

// Check length, in characters
System.out.println(string.length()); // prints "11"

// Check encoded sizes
final byte[] utf8Bytes = string.getBytes("UTF-8");
System.out.println(utf8Bytes.length); // prints "11"

final byte[] utf16Bytes= string.getBytes("UTF-16");
System.out.println(utf16Bytes.length); // prints "24"

final byte[] utf32Bytes = string.getBytes("UTF-32");
System.out.println(utf32Bytes.length); // prints "44"

final byte[] isoBytes = string.getBytes("ISO-8859-1");
System.out.println(isoBytes.length); // prints "11"

final byte[] winBytes = string.getBytes("CP1252");
System.out.println(winBytes.length); // prints "11"

Veja bem, mesmo uma simples string "ASCII" pode ter um número diferente de bytes em sua representação, dependendo da codificação usada. Use o conjunto de caracteres de seu interesse para o seu caso, como argumento getBytes(). E não caia na armadilha de supor que UTF-8 represente todos os caracteres como um único byte, pois isso também não é verdade:

final String interesting = "\uF93D\uF936\uF949\uF942"; // Chinese ideograms

// Check length, in characters
System.out.println(interesting.length()); // prints "4"

// Check encoded sizes
final byte[] utf8Bytes = interesting.getBytes("UTF-8");
System.out.println(utf8Bytes.length); // prints "12"

final byte[] utf16Bytes= interesting.getBytes("UTF-16");
System.out.println(utf16Bytes.length); // prints "10"

final byte[] utf32Bytes = interesting.getBytes("UTF-32");
System.out.println(utf32Bytes.length); // prints "16"

final byte[] isoBytes = interesting.getBytes("ISO-8859-1");
System.out.println(isoBytes.length); // prints "4" (probably encoded "????")

final byte[] winBytes = interesting.getBytes("CP1252");
System.out.println(winBytes.length); // prints "4" (probably encoded "????")

(Observe que, se você não fornecer um argumento para o conjunto de caracteres, o conjunto de caracteres padrão da plataforma será usado. Isso pode ser útil em alguns contextos, mas, em geral, você deve evitar os padrões e sempre usar um conjunto explícito de caracteres ao codificar / decodificação.)

Andrzej Doyle
fonte
1
. por isso novamente se eu usar getBytes () ele vai me dar o comprimento igual x.length estou errado eu, porque eu não tenho certeza
Verde
4
@ Green Ash O comprimento da matriz de bytes - getBytes () - e x.length PODE ser igual, mas não é garantido que seja. Será igual se todos os caracteres forem representados por um único byte cada. Isso sempre será verdadeiro para codificações de caracteres que usam um único byte por caractere (ou menos), como ISO-8859-1. O UTF-8 usa 1 ou 2 bytes, portanto depende dos caracteres exatos na sequência. Depois, há codificações de caracteres que sempre usam dois bytes por caractere.
Kris
eu gosto da sua resposta :), então eles podem ser de alguma forma iguais, mas nem sempre eu estou certo? ok então é ok usar o método sem o parâmetro porque está me causando um erro !!
Verde
@ O ponto verde é que o número de bytes nem sempre é igual ao número de caracteres . O número de bytes depende da codificação de caracteres usada. Você precisará saber qual codificação de caracteres usará e levar isso em conta. que erro você está tendo? Se você apenas o usar getBytes(), usará a codificação de caracteres padrão do seu sistema.
Jesper
1
@KorayTugay Sim, mais ou menos. Você pode discutir sobre a ordem de causa e efeito, no entanto. Eu estaria mais inclinado a afirmar que um caractere sempre tem 2 bytes, porque é um tipo de dados primitivo definido para ter 2 bytes de largura. (E que a representação UTF-16 era principalmente uma consequência deste, ao invés do contrário.)
Andrzej Doyle
63

Se você estiver executando com referências de 64 bits:

sizeof(string) = 
8 + // object header used by the VM
8 + // 64-bit reference to char array (value)
8 + string.length() * 2 + // character array itself (object header + 16-bit chars)
4 + // offset integer
4 + // count integer
4 + // cached hash code

Em outras palavras:

sizeof(string) = 36 + string.length() * 2

Em uma VM de 32 bits ou de 64 bits com OOPs compactados (-XX: + UseCompressedOops), as referências são de 4 bytes. Portanto, o total seria:

sizeof(string) = 32 + string.length() * 2

Isso não leva em consideração as referências ao objeto string.

roozbeh
fonte
6
Eu estava assumindo que a pergunta era sobre o número de bytes alocados na memória para um objeto String. Se a pergunta é sobre o número de bytes necessários para serializar a String, como outros indicaram, isso depende da codificação usada.
Roozbeh
2
Fonte para sua resposta? Graças
Luna
1
Nota: sizeofdeve ser múltiplo de 8.
dieter
19

A resposta pedante (embora não necessariamente a mais útil, dependendo do que você quer fazer com o resultado) é:

string.length() * 2

As seqüências Java são fisicamente armazenadas na UTF-16BEcodificação, que usa 2 bytes por unidade de código e String.length()mede o comprimento em unidades de código UTF-16, portanto, isso é equivalente a:

final byte[] utf16Bytes= string.getBytes("UTF-16BE");
System.out.println(utf16Bytes.length);

E isso informará o tamanho da charmatriz interna , em bytes .

Nota: "UTF-16"fornecerá um resultado diferente, "UTF-16BE"pois a codificação anterior inserirá uma lista técnica , adicionando 2 bytes ao comprimento da matriz.

finnw
fonte
A resposta de Roozbeh é melhor, porque leva em consideração os outros bytes também.
Lodewijk Bogaards 30/03/19
@finnw Tem certeza de que a codificação é UTF-16BE e não UTF-16? De acordo com a classe String Javadoc ( docs.oracle.com/javase/6/docs/api/java/lang/String.html ), "Uma String representa uma string no formato UTF-16 ...".
entpnerd
17

De acordo com Como converter seqüências de caracteres para e de matrizes de bytes UTF8 em Java :

String s = "some text here";
byte[] b = s.getBytes("UTF-8");
System.out.println(b.length);
Boris Pavlović
fonte
mas desculpe-me quando compilo seu código, isso me dá um erro; por causa do parâmetro "UTF-8" .where, quando passo um parâmetro vazio, me dá o mesmo comprimento que x.length. Eu entendi mal o conceito. ajuda por favor
Green
@ Green Ash, qual versão do Java você possui?
Buhake Sindi
@ Green Ash, que exceção você está recebendo?
Buhake Sindi
2
para ficar claro, esta é a saída: test.java:11: exceção não relatada java.io.UnsupportedEncodingException; deve ser capturado ou declarado como acionado byte [] b = s.getBytes ("UTF-8"); ^ 1 erro Processo concluído.
Verde
3
@Green, tente: s.getBytes(Charset.forName("UTF-8")).
James.garriss
10

Uma Stringinstância aloca uma certa quantidade de bytes na memória. Talvez você esteja olhando para algo comosizeof("Hello World") que retornaria o número de bytes alocados pela própria estrutura de dados?

Em Java, geralmente não há necessidade de uma sizeoffunção, porque nunca alocamos memória para armazenar uma estrutura de dados. Podemos dar uma olhada no String.javaarquivo para obter uma estimativa aproximada, e vemos alguns 'int', algumas referências e a char[]. A especificação da linguagem Java define, que charvaria de 0 a 65535, portanto, dois bytes são suficientes para manter um único caractere na memória. Mas uma JVM não precisa armazenar um caractere em 2 bytes, apenas tem que garantir que a implementação dechar possa conter valores do intervalo define.

Então, sizeofrealmente não faz sentido em Java. Mas, supondo que tenhamos uma String grande e uma charaloque dois bytes, o espaço ocupado pela memória de um Stringobjeto será pelo menos 2 * str.length()em bytes.

Andreas Dolk
fonte
7

Existe um método chamado getBytes () . Use com sabedoria.

Andrei Ciobanu
fonte
17
Sabiamente = não use aquele sem um parâmetro de conjunto de caracteres.
Thilo
Por quê? Isso é um problema se eu configurar meu ambiente para executar com a codificação UTF8?
Ziggy
1
O getBytes também criará e copiará a matriz de bytes; portanto, se você estiver falando de cadeias longas, essa operação poderá ficar cara.
ticktock
@ticktock, se você ainda está por perto, sim, mas qual é a alternativa? Cheguei aqui esperando que uma função de biblioteca retornasse o armazenamento necessário para que eu pudesse combiná-lo em uma alocação maior.
SensorSmith 18/03
4

Tente o seguinte:

Bytes.toBytes(x).length

Supondo que você declarou e inicializou x antes

formiga
fonte
3
Isso faz parte da biblioteca Java padrão? Não consigo encontrar a Bytesturma.
Kröw 04/07/19
0

Para evitar tentar capturar, use:

String s = "some text here";
byte[] b = s.getBytes(StandardCharsets.UTF_8);
System.out.println(b.length);
radu_paun
fonte