Byte di una stringa in Java


179

In Java, se ho una stringa x, come posso calcolare il numero di byte in quella stringa?


15
È possibile che si desideri utilizzare una stringa per rappresentare il corpo di una risposta HTTP e utilizzare la dimensione per impostare l'intestazione "Content-Length", che è specificata in ottetti / byte e non caratteri. w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13
iX3

4
Una colonna del database può avere limiti di lunghezza in byte, ad es. VARCHAR2 (4000 BYTE) in Oracle. Si potrebbe voler conoscere il conteggio dei byte di una stringa nella codifica desiderata per sapere se la stringa si adatterebbe.
Somu,

@ iX3 Esattamente come stavo cercando di fare.
MC Emperor

1
Credo che ci siano due possibili interpretazioni di questa domanda, a seconda dell'intento: uno è "quanta memoria usa la mia stringa?". La risposta è fornita da @roozbeh di seguito (forse sottigliezze modulo VM come OOPS compresso). L'altro è "se convertissi la stringa in un byte [] quanta memoria userebbe quell'array di byte?". Questa è la domanda a cui risponde Andrzej Doyle. La differenza può essere grande: "Hello World" in UTF8 è di 11 byte, ma la stringa (per @roozbeh) è di 50 byte (se la mia matematica è corretta).
L. Blanc,

Avrei dovuto aggiungere che gli 11 byte non includono il sovraccarico dell'oggetto byte [] che li contiene, quindi il confronto è in qualche modo fuorviante.
L. Blanc,

Risposte:


289

Una stringa è un elenco di caratteri (ovvero punti di codice). Il numero di byte utilizzati per rappresentare la stringa dipende interamente dalla codifica utilizzata per trasformarla in byte .

Detto questo, puoi trasformare la stringa in una matrice di byte e quindi guardare le sue dimensioni come segue:

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

Come vedi, anche una semplice stringa "ASCII" può avere un numero diverso di byte nella sua rappresentazione, a seconda della codifica utilizzata. Usa qualsiasi set di caratteri che ti interessa per il tuo caso, come argomento a getBytes(). E non cadere nella trappola di supporre che UTF-8 rappresenti ogni carattere come un singolo byte, dato che non è neanche vero:

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

(Tieni presente che se non fornisci un argomento del set di caratteri, viene utilizzato il set di caratteri predefinito della piattaforma . Ciò potrebbe essere utile in alcuni contesti, ma in generale dovresti evitare a seconda delle impostazioni predefinite e utilizzare sempre un set di caratteri esplicito durante la codifica / è richiesta la decodifica.)


1
quindi di nuovo se uso getBytes (). Mi darà la stessa lunghezza di x.length se sbaglio perché non ne sono sicuro
Green

4
@Green Ash La lunghezza dell'array di byte - getBytes () - e x.length POTREBBE essere uguale ma non è garantito che sia così. Sarà uguale se tutti i caratteri sono rappresentati da un singolo byte ciascuno. Ciò sarà sempre vero per le codifiche dei caratteri che utilizzano un singolo byte per carattere (o meno), come ISO-8859-1. UTF-8 utilizza 1 o 2 byte, quindi dipende dai caratteri esatti nella stringa. Quindi ci sono codifiche di caratteri che usano sempre due byte per carattere.
Kris

mi piace la tua risposta :), quindi potrebbero in qualche modo essere uguali ma non sempre ho ragione? ok allora va bene usare il metodo senza il parametro perché mi causa un errore !!
Green

@Il punto verde è che il numero di byte non è sempre uguale al numero di caratteri . Il numero di byte dipende dalla codifica dei caratteri utilizzata. Dovrai sapere quale codifica dei caratteri userai e tenerne conto. Che errore stai ricevendo? Se lo usi getBytes(), utilizzerà la codifica dei caratteri predefinita del tuo sistema.
Jesper,

1
@KorayTugay Sì, più o meno. Tuttavia, potresti discutere sull'ordine di causa ed effetto. Sarei più propenso a dichiarare che un carattere è sempre di 2 byte perché è un tipo di dati primitivo definito come largo 2 byte. (E che la rappresentazione UTF-16 era principalmente una conseguenza di ciò, piuttosto che il contrario).
Andrzej Doyle,

63

Se si esegue con riferimenti a 64 bit:

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

In altre parole:

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

Su una macchina virtuale a 32 bit o una macchina virtuale a 64 bit con OOP compressi (-XX: + UseCompressedOops), i riferimenti sono 4 byte. Quindi il totale sarebbe:

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

Ciò non tiene conto dei riferimenti all'oggetto stringa.


6
Supponevo che la domanda riguardasse il numero di byte allocati in memoria per un oggetto String. Se la domanda riguarda il numero di byte necessari per serializzare la stringa, come altri hanno sottolineato, dipende dalla codifica utilizzata.
roozbeh,

2
Fonte per la tua risposta? Grazie
mavis,

1
Nota: sizeofdovrebbe essere multiplo di 8.
Dieter,

19

La risposta pedante (anche se non necessariamente la più utile, a seconda di cosa vuoi fare con il risultato) è:

string.length() * 2

Le stringhe Java sono archiviate fisicamente nella UTF-16BEcodifica, che utilizza 2 byte per unità di codice e String.length()misura la lunghezza in unità di codice UTF-16, quindi questo equivale a:

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

E questo ti dirà la dimensione chardell'array interno , in byte .

Nota: "UTF-16"darà un risultato diverso da "UTF-16BE"come la precedente codifica inserirà una DBA , aggiungendo 2 byte alla lunghezza dell'array.


La risposta di Roozbeh è migliore, perché tiene conto anche degli altri byte.
Lodewijk Bogaards,

@finnw Sei sicuro che la codifica sia UTF-16BE e non UTF-16? Secondo la classe String Javadoc ( docs.oracle.com/javase/6/docs/api/java/lang/String.html ), "Una stringa rappresenta una stringa nel formato UTF-16 ...".
entpnerd,

17

Secondo Come convertire le stringhe da e verso array di byte UTF8 in Java :

String s = "some text here";
byte[] b = s.getBytes("UTF-8");
System.out.println(b.length);

ma scusami quando compilo il tuo codice mi dà un errore; a causa del parametro "UTF-8". dove quando passo un parametro vuoto mi dà la stessa lunghezza di x.length. fraintendo il concetto. aiuto per favore
Green

@ Green Ash, che versione di Java hai?
Buhake Sindi,

@ Green Ash, che eccezione stai ottenendo?
Buhake Sindi,

2
per essere chiari questo è l'output: test.java:11: eccezione non dichiarata java.io.UnsupportedEncodingException; deve essere catturato o dichiarato essere lanciato byte [] b = s.getBytes ("UTF-8"); ^ 1 errore Processo completato.
Verde

3
@Green, provare: s.getBytes(Charset.forName("UTF-8")).
james.garriss,

10

Un Stringesempio alloca una certa quantità di byte in memoria. Forse stai osservando qualcosa del genere sizeof("Hello World")che restituirebbe il numero di byte allocati dalla stessa struttura dati?

In Java, di solito non è necessaria una sizeoffunzione, perché non allociamo mai memoria per memorizzare una struttura di dati. Possiamo dare un'occhiata al String.javafile per una stima approssimativa, e vediamo alcuni 'int', alcuni riferimenti e a char[]. La specifica del linguaggio Java definisce che un charintervallo va da 0 a 65535, quindi due byte sono sufficienti per mantenere un singolo carattere in memoria. Ma una JVM non deve archiviare un carattere in 2 byte, deve solo garantire che l'implementazione di charpuò contenere valori dell'intervallo definito.

Quindi sizeofdavvero non ha alcun senso in Java. Ma supponendo che abbiamo una stringa di grandi dimensioni e una charalloca due byte, l'impronta di memoria di un Stringoggetto è almeno 2 * str.length()in byte.


7

C'è un metodo chiamato getBytes () . Usalo saggiamente.


17
Saggiamente = non usare quello senza un parametro set di caratteri.
Thilo,

Perché? È un problema se configuro il mio ambiente per l'esecuzione con la codifica UTF8?
ziggy,

1
getBytes creerà e copierà anche l'array di byte, quindi se stai parlando di stringhe lunghe, questa operazione potrebbe essere costosa.
ticktock

@ticktock, se sei ancora in giro, sì ma qual è l'alternativa? Sono arrivato qui sperando in una funzione di libreria per restituire lo spazio di archiviazione necessario in modo da poterlo combinare in una allocazione più ampia.
SensorSmith il

4

Prova questo :

Bytes.toBytes(x).length

Supponendo di aver dichiarato e inizializzato x prima


3
Questa parte della libreria Java standard? Non riesco a trovare la Byteslezione.
Kröw,

0

Per evitare di provare, utilizzare:

String s = "some text here";
byte[] b = s.getBytes(StandardCharsets.UTF_8);
System.out.println(b.length);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.