Bytes de una cadena en Java

179

En Java, si tengo una cadena x, ¿cómo puedo calcular el número de bytes en esa cadena?

Verde
fuente
15
Es posible que desee usar una cadena para representar el cuerpo de una respuesta HTTP y usar el tamaño para establecer el encabezado "Content-Length", que se especifica en octetos / bytes, no en caracteres. w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13
iX3
44
Una columna de base de datos puede tener restricción de longitud en bytes, por ejemplo, VARCHAR2 (4000 BYTE) en Oracle. Es posible que desee saber el recuento de bytes de una cadena en la codificación deseada para saber si la cadena encajaría.
Somu
@ iX3 Exactamente lo mismo que estaba tratando de hacer.
MC Emperor
1
Creo que hay dos posibles interpretaciones de esta pregunta, dependiendo de la intención: una es "¿cuánta memoria usa mi String?". La respuesta a eso la proporciona @roozbeh a continuación (tal vez sutilezas de módulo VM como OOPS comprimido). La otra es, "si convierto la cadena a un byte [], ¿cuánta memoria usaría esa matriz de bytes?". Esta es la pregunta que responde Andrzej Doyle. La diferencia puede ser grande: "Hello World" en UTF8 es de 11 bytes, pero la Cadena (por @roozbeh) es de 50 bytes (si mis cálculos son correctos).
L. Blanc
Debería haber agregado que los 11 bytes no incluyen la sobrecarga del objeto byte [] que los contiene, por lo que la comparación es algo engañosa.
L. Blanc

Respuestas:

289

Una cadena es una lista de caracteres (es decir, puntos de código). La cantidad de bytes que se toman para representar la cadena depende completamente de la codificación que use para convertirla en bytes .

Dicho esto, puede convertir la cadena en una matriz de bytes y luego ver su tamaño de la siguiente manera:

// 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"

Como puede ver, incluso una cadena simple "ASCII" puede tener un número diferente de bytes en su representación, dependiendo de la codificación utilizada. Utilice el conjunto de caracteres que le interese para su caso, como argumento para getBytes(). Y no caigas en la trampa de asumir que UTF-8 representa a cada personaje como un solo byte, ya que eso tampoco es cierto:

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 "????")

(Tenga en cuenta que si no proporciona un argumento de juego de caracteres, se usa el juego de caracteres predeterminado de la plataforma . Esto puede ser útil en algunos contextos, pero en general debe evitar depender de los valores predeterminados y siempre usar un juego de caracteres explícito al codificar / Se requiere decodificación.)

Andrzej Doyle
fuente
1
así que de nuevo si uso getBytes (). me dará la misma longitud que x.length estoy equivocado porque no estoy seguro
Verde
44
@Green Ash La longitud de la matriz de bytes - getBytes () - y x.length PUEDEN ser igual pero no se garantiza que lo sea. Será igual si todos los caracteres están representados por un solo byte cada uno. Esto siempre será válido para las codificaciones de caracteres que usan un solo byte por carácter (o menos), como ISO-8859-1. UTF-8 usa 1 o 2 bytes, por lo que depende de los caracteres exactos en la cadena. Luego están las codificaciones de caracteres que siempre usan dos bytes por carácter.
Kris
me gusta tu respuesta :), por lo que de alguna manera podrían ser las mismas, pero no siempre estoy en lo cierto. ok, entonces está bien usar el método sin el parámetro porque me causa un error !!
Verde
@Verde el punto es que el número de bytes no siempre es igual al número de caracteres . El número de bytes depende de la codificación de caracteres que se utiliza. Tendrá que saber qué codificación de caracteres utilizará y tenerlo en cuenta. ¿Qué error estás recibiendo? Si solo lo usa getBytes(), usará la codificación de caracteres predeterminada de su sistema.
Jesper
1
@KorayTugay Sí, más o menos. Sin embargo, podría discutir sobre el orden de causa y efecto. Me inclinaría más a decir que un carácter siempre tiene 2 bytes porque es un tipo de datos primitivo definido para tener 2 bytes de ancho. (Y que la representación de UTF-16 fue principalmente una consecuencia de esto, y no al revés.)
Andrzej Doyle
63

Si está ejecutando con referencias 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

En otras palabras:

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

En una máquina virtual de 32 bits o una máquina virtual de 64 bits con OOP comprimidos (-XX: + UseCompressedOops), las referencias son de 4 bytes. Entonces el total sería:

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

Esto no tiene en cuenta las referencias al objeto de cadena.

roozbeh
fuente
66
Asumí que la pregunta era sobre el número de bytes asignados en la memoria para un objeto String. Si la pregunta es sobre el número de bytes necesarios para serializar la Cadena, como han señalado otros, depende de la codificación utilizada.
roozbeh
2
Fuente de su respuesta? Gracias
mavis
1
Nota: sizeofdebe ser múltiplo de 8.
Dieter
19

La respuesta pedante (aunque no necesariamente la más útil, dependiendo de lo que quieras hacer con el resultado) es:

string.length() * 2

Las cadenas de Java se almacenan físicamente en la UTF-16BEcodificación, que utiliza 2 bytes por unidad de código, y String.length()mide la longitud en unidades de código UTF-16, por lo que esto es equivalente a:

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

Y esto le dirá el tamaño de la charmatriz interna , en bytes .

Nota: "UTF-16"dará un resultado diferente "UTF-16BE"ya que la codificación anterior insertará una lista de materiales , agregando 2 bytes a la longitud de la matriz.

finnw
fuente
La respuesta de Roozbeh es mejor, porque también tiene en cuenta los otros bytes.
Lodewijk Bogaards
@finnw ¿Está seguro de que la codificación es UTF-16BE y no UTF-16? De acuerdo con la clase String Javadoc ( docs.oracle.com/javase/6/docs/api/java/lang/String.html ), "Una cadena representa una cadena en el formato UTF-16 ...".
entpnerd
17

De acuerdo con Cómo convertir cadenas hacia y desde matrices de bytes UTF8 en Java :

String s = "some text here";
byte[] b = s.getBytes("UTF-8");
System.out.println(b.length);
Boris Pavlović
fuente
pero discúlpeme cuando compilo su código, me da un error; debido al parámetro "UTF-8". Cuando paso un parámetro vacío, me da la misma longitud que x.length. No entiendo el concepto. ayuda por favor
Verde
@ Green Ash, ¿qué versión de Java tienes?
Buhake Sindi
@ Green Ash, ¿qué excepción estás recibiendo?
Buhake Sindi
2
para que quede claro, esta es la salida: test.java:11: excepción no notificada java.io.UnsupportedEncodingException; debe ser capturado o declarado para ser lanzado byte [] b = s.getBytes ("UTF-8"); ^ 1 error Proceso completado.
Verde
3
@Green, Proveedores: s.getBytes(Charset.forName("UTF-8")).
james.garriss
10

Una Stringinstancia asigna una cierta cantidad de bytes en la memoria. ¿Quizás esté viendo algo como sizeof("Hello World")lo que devolvería el número de bytes asignados por la estructura de datos en sí?

En Java, generalmente no hay necesidad de una sizeoffunción, porque nunca asignamos memoria para almacenar una estructura de datos. Podemos echar un vistazo al String.javaarchivo para una estimación aproximada, y vemos algunos 'int', algunas referencias y a char[]. La especificación del lenguaje Java define que un charrango va de 0 a 65535, por lo que dos bytes son suficientes para mantener un único carácter en la memoria. Pero una JVM no tiene que almacenar un carácter en 2 bytes, solo tiene que garantizar que la implementación de charpuede contener valores del rango definido.

Entonces sizeofrealmente no tiene ningún sentido en Java. Pero, suponiendo que tenemos una cadena grande y una charasigna dos bytes, la huella de memoria de un Stringobjeto es al menos 2 * str.length()en bytes.

Andreas Dolk
fuente
7

Hay un método llamado getBytes () . Úsalo con sabiduría .

Andrei Ciobanu
fuente
17
Sabiamente = no uses el que no tenga un parámetro de juego de caracteres.
Thilo
¿Por qué? ¿Es este un problema si configuro mi entorno para que se ejecute con codificación UTF8?
ziggy
1
getBytes también creará y copiará la matriz de bytes, por lo que si está hablando de cadenas largas, esta operación podría ser costosa.
ticktock
@ticktock, si todavía estás cerca, sí, pero ¿cuál es la alternativa? Llegué esperando que una función de biblioteca devolviera el almacenamiento necesario para poder combinarlo en una asignación más grande.
SensorSmith
4

Prueba esto :

Bytes.toBytes(x).length

Asumiendo que declaraste e inicializaste x antes

hormiga
fuente
3
¿Es esto parte de la biblioteca estándar de Java? No puedo encontrar la Bytesclase.
Kröw
0

Para evitar intentar atrapar, use:

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