Bytes einer Zeichenfolge in Java

179

xWie kann ich in Java, wenn ich eine Zeichenfolge habe, die Anzahl der Bytes in dieser Zeichenfolge berechnen?

Grün
quelle
15
Möglicherweise möchten Sie einen String verwenden, um den Hauptteil einer HTTP-Antwort darzustellen, und die Größe verwenden, um den Header "Content-Length" festzulegen, der in Oktetten / Bytes und nicht in Zeichen angegeben wird. w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13
iX3
4
Eine Datenbankspalte kann eine Längenbeschränkung in Bytes aufweisen, z. B. VARCHAR2 (4000 BYTE) in Oracle. Möglicherweise möchten Sie die Byteanzahl eines Strings in der gewünschten Codierung kennen, um zu wissen, ob der String passt.
Somu
@ iX3 Genau das gleiche wie ich versucht habe.
MC Emperor
1
Ich glaube, es gibt zwei mögliche Interpretationen dieser Frage, abhängig von der Absicht: Eine ist "Wie viel Speicher verwendet mein String?". Die Antwort darauf liefert @roozbeh unten (möglicherweise Modulo-VM-Feinheiten wie komprimiertes OOPS). Die andere lautet: "Wenn ich die Zeichenfolge in ein Byte [] konvertiere, wie viel Speicher würde dieses Byte-Array verwenden?". Dies ist die Frage, die von Andrzej Doyle beantwortet wird. Der Unterschied kann groß sein: "Hello World" in UTF8 ist 11 Bytes, aber der String (per @roozbeh) ist 50 Bytes (wenn meine Mathematik stimmt).
L. Blanc
Ich hätte hinzufügen sollen, dass die 11 Bytes nicht den Overhead des Byte [] -Objekts enthalten, das sie enthält, daher ist der Vergleich etwas irreführend.
L. Blanc

Antworten:

289

Eine Zeichenfolge ist eine Liste von Zeichen (dh Codepunkten). Die Anzahl der Bytes, die zur Darstellung der Zeichenfolge benötigt werden hängt vollständig davon ab, welche Codierung Sie verwenden, um sie in Bytes umzuwandeln .

Sie können den String jedoch in ein Byte-Array umwandeln und dann seine Größe wie folgt betrachten:

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

Sie sehen also, dass selbst eine einfache "ASCII" -String in ihrer Darstellung eine unterschiedliche Anzahl von Bytes haben kann, je nachdem, welche Codierung verwendet wird. Verwenden Sie den gewünschten Zeichensatz für Ihren Fall als Argument dafür getBytes(). Und geraten Sie nicht in die Falle, anzunehmen, dass UTF-8 jedes Zeichen als einzelnes Byte darstellt, da dies auch nicht zutrifft:

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

(Beachten Sie, dass der Standardzeichensatz der Plattform verwendet wird, wenn Sie kein Zeichensatzargument angeben . Dies kann in einigen Kontexten nützlich sein. Im Allgemeinen sollten Sie jedoch die Abhängigkeit von den Standardeinstellungen vermeiden und beim Codieren / immer einen expliziten Zeichensatz verwenden Dekodierung ist erforderlich.)

Andrzej Doyle
quelle
1
Also nochmal, wenn ich getBytes () benutze. Es gibt mir die gleiche Länge wie x.Länge. Bin ich falsch, weil ich nicht sicher bin
Grün
4
@Green Ash Die Länge des Byte-Arrays - getBytes () - und x.length kann gleich sein, kann aber nicht garantiert werden. Es ist gleich, wenn alle Zeichen jeweils durch ein einzelnes Byte dargestellt werden. Dies gilt immer für Zeichencodierungen, die ein einzelnes Byte pro Zeichen (oder weniger) verwenden, z. B. ISO-8859-1. UTF-8 verwendet entweder 1 oder 2 Bytes, daher hängt es von den genauen Zeichen in der Zeichenfolge ab. Dann gibt es Zeichencodierungen, die immer zwei Bytes pro Zeichen verwenden.
Kris
Ich mag deine Antwort :), also könnten sie irgendwie gleich sein, aber nicht immer habe ich recht? ok dann ist es ok die methode ohne den parameter zu benutzen weil es mir einen fehler verursacht !!
Grün
@Green der Punkt ist, dass die Anzahl der Bytes nicht immer der Anzahl der Zeichen entspricht . Die Anzahl der Bytes hängt von der verwendeten Zeichenkodierung ab. Sie müssen wissen, welche Zeichenkodierung Sie verwenden werden, und dies berücksichtigen. Welchen Fehler bekommen Sie? Wenn Sie nur verwenden getBytes(), wird die Standardzeichenkodierung Ihres Systems verwendet.
Jesper
1
@KorayTugay Ja, mehr oder weniger. Sie könnten jedoch über die Reihenfolge von Ursache und Wirkung streiten. Ich würde mehr in dem Zustand geneigt sein , dass ein char ist immer 2 Bytes , weil es dich um einen primitiven Datentyp definierte 2 Bytes breit zu sein. (Und dass die UTF-16-Darstellung hauptsächlich eine Folge davon war und nicht umgekehrt.)
Andrzej Doyle
63

Wenn Sie mit 64-Bit-Referenzen arbeiten:

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

Mit anderen Worten:

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

Auf einer 32-Bit-VM oder einer 64-Bit-VM mit komprimierten OOPs (-XX: + UseCompressedOops) sind die Referenzen 4 Byte. Die Summe wäre also:

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

Dies berücksichtigt nicht die Verweise auf das Zeichenfolgenobjekt.

roozbeh
quelle
6
Ich nahm an, dass die Frage die Anzahl der im Speicher für ein String-Objekt zugewiesenen Bytes betraf. Wenn es um die Anzahl der Bytes geht, die zum Serialisieren des Strings erforderlich sind, hängt dies von der verwendeten Codierung ab.
Roozbeh
2
Quelle für Ihre Antwort? Danke
Mavis
1
Hinweis: sizeofsollte ein Vielfaches von 8 sein.
Dieter
19

Die pedantische Antwort (obwohl nicht unbedingt die nützlichste, je nachdem, was Sie mit dem Ergebnis machen möchten) lautet:

string.length() * 2

Java-Zeichenfolgen werden physisch in der UTF-16BECodierung gespeichert , die 2 Bytes pro Codeeinheit verwendet und String.length()die Länge in UTF-16-Codeeinheiten misst. Dies entspricht also:

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

Und dies zeigt Ihnen die Größe des internen charArrays in Bytes .

Hinweis: "UTF-16"Gibt ein anderes Ergebnis "UTF-16BE"als die vorherige Codierung, fügt eine Stückliste ein und addiert 2 Bytes zur Länge des Arrays.

finnw
quelle
Roozbehs Antwort ist besser, weil sie auch die anderen Bytes berücksichtigt.
Lodewijk Bogaards
@finnw Sind Sie sicher, dass die Codierung UTF-16BE und nicht UTF-16 ist? Gemäß der String-Klasse Javadoc ( docs.oracle.com/javase/6/docs/api/java/lang/String.html ) steht "Ein String für einen String im UTF-16-Format ...".
Entpnerd
17

Laut Wie konvertiert Strings zu und von UTF8 Byte - Arrays in Java :

String s = "some text here";
byte[] b = s.getBytes("UTF-8");
System.out.println(b.length);
Boris Pavlović
quelle
aber entschuldigen Sie, wenn ich Ihren Code kompiliere, gibt es mir einen Fehler; Aufgrund des Parameters "UTF-8". Wenn ich einen leeren Parameter übergebe, erhalte ich die gleiche Länge wie x.length. Ich verstehe das Konzept falsch. Hilfe bitte
Grün
@ Green Ash, welche Java-Version hast du?
Buhake Sindi
@ Green Ash, welche Ausnahme bekommst du?
Buhake Sindi
2
um klar zu sein, ist dies die Ausgabe: test.java:11: nicht gemeldete Ausnahme java.io.UnsupportedEncodingException; muss abgefangen oder deklariert werden, um geworfen zu werden byte [] b = s.getBytes ("UTF-8"); ^ 1 Fehler Vorgang abgeschlossen.
Grün
3
@Green, versuchen Sie : s.getBytes(Charset.forName("UTF-8")).
James.garriss
10

Eine StringInstanz weist eine bestimmte Anzahl von Bytes im Speicher zu. Vielleicht schaust du dir so etwas ansizeof("Hello World") das die Anzahl der von der Datenstruktur selbst zugewiesenen Bytes zurückgibt?

In Java ist normalerweise keine sizeofFunktion erforderlich , da wir niemals Speicher zum Speichern einer Datenstruktur zuweisen. Wir können uns die String.javaDatei ansehen, um eine grobe Schätzung zu erhalten, und wir sehen einige 'int', einige Referenzen und a char[]. Das Java-Sprachspezifikation definiert, dass a charzwischen 0 und 65535 liegt, sodass zwei Bytes ausreichen, um ein einzelnes Zeichen im Speicher zu halten. Aber eine JVM muss nicht ein Zeichen in 2 Bytes speichern, sondern nur garantieren, dass die Implementierung vonchar Werte des definierten Bereichs enthalten kann.

Also sizeofmacht das in Java wirklich keinen Sinn. Unter der Annahme, dass wir einen großen String haben und einer charzwei Bytes zuweist, Stringbeträgt der Speicherbedarf eines Objekts mindestens 2 * str.length()Bytes.

Andreas Dolk
quelle
7

Es gibt eine Methode namens getBytes () . Benutze es weise .

Andrei Ciobanu
quelle
17
Mit Bedacht = Verwenden Sie keinen Parameter ohne Zeichensatz.
Thilo
Warum? Ist dies ein Problem, wenn ich meine Umgebung so konfiguriere, dass sie mit UTF8-Codierung ausgeführt wird?
Zicky
1
getBytes erstellt und kopiert auch das Array von Bytes. Wenn Sie also lange Zeichenfolgen sprechen, kann dieser Vorgang teuer werden.
Ticktock
@ticktock, wenn du noch da bist, ja aber was ist die Alternative? Ich bin hierher gekommen und habe gehofft, dass eine Bibliotheksfunktion den benötigten Speicher zurückgibt, damit ich ihn zu einer größeren Zuordnung kombinieren kann.
SensorSmith
4

Versuche dies :

Bytes.toBytes(x).length

Angenommen, Sie haben x zuvor deklariert und initialisiert

Ameise
quelle
3
Ist dies Teil der Standard-Java-Bibliothek? Ich kann die BytesKlasse nicht finden .
Kröw
0

Verwenden Sie:

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