Octets d'une chaîne en Java

179

En Java, si j'ai une chaîne x, comment puis-je calculer le nombre d'octets dans cette chaîne?

vert
la source
15
On peut souhaiter utiliser une chaîne pour représenter le corps d'une réponse HTTP et utiliser la taille pour définir l'en-tête "Content-Length", qui est spécifié en octets / octets et non en caractères. w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13
iX3
4
Une colonne de base de données peut avoir une restriction de longueur en octets, par exemple VARCHAR2 (4000 BYTE) dans Oracle. On peut souhaiter connaître le nombre d'octets d'une chaîne dans le codage souhaité pour savoir si la chaîne conviendrait.
Somu le
@ iX3 Exactement la même chose que j'essayais de faire.
MC Emperor
1
Je crois qu'il y a deux interprétations possibles de cette question, selon l'intention: L'une est "combien de mémoire ma chaîne utilise-t-elle?". La réponse à cela est fournie par @roozbeh ci-dessous (peut-être des subtilités modulo VM telles que OOPS compressé). L'autre est, "si je convertis la chaîne en octet [], combien de mémoire ce tableau d'octets utiliserait-il?". Telle est la question à laquelle répond Andrzej Doyle. La différence peut être importante: "Hello World" en UTF8 est de 11 octets, mais la chaîne (par @roozbeh) est de 50 octets (si mes calculs sont corrects).
L. Blanc
J'aurais dû ajouter que les 11 octets n'incluent pas la surcharge de l'objet byte [] qui les contient, donc la comparaison est quelque peu trompeuse.
L. Blanc

Réponses:

289

Une chaîne est une liste de caractères (c'est-à-dire des points de code). Le nombre d'octets pris pour représenter la chaîne dépend entièrement du codage que vous utilisez pour la transformer en octets .

Cela dit, vous pouvez transformer la chaîne en un tableau d'octets, puis examiner sa taille comme suit:

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

Ainsi vous voyez, même une simple chaîne "ASCII" peut avoir un nombre d'octets différent dans sa représentation, selon le codage utilisé. Utilisez le jeu de caractères qui vous intéresse pour votre cas, comme argument getBytes(). Et ne tombez pas dans le piège de supposer que UTF-8 représente chaque caractère comme un seul octet, car ce n'est pas vrai non plus:

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

(Notez que si vous ne fournissez pas d'argument de jeu de caractères, le jeu de caractères par défaut de la plate-forme est utilisé. Cela peut être utile dans certains contextes, mais en général, vous devez éviter de dépendre des valeurs par défaut et toujours utiliser un jeu de caractères explicite lors de l'encodage / le décodage est nécessaire.)

Andrzej Doyle
la source
1
donc encore une fois si j'utilise getBytes (). cela me donnera la même longueur que x.length je me trompe parce que je ne suis pas sûr
Vert
4
@Green Ash La longueur du tableau d'octets - getBytes () - et x.length PEUVENT être égales mais ce n'est pas garanti. Il sera égal si tous les caractères sont représentés chacun par un seul octet. Cela sera toujours vrai pour les encodages de caractères qui utilisent un seul octet par caractère (ou moins), comme ISO-8859-1. UTF-8 utilise 1 ou 2 octets, donc cela dépend des caractères exacts de la chaîne. Ensuite, il existe des encodages de caractères qui utilisent toujours deux octets par caractère.
Kris
j'aime ta réponse :), donc ils pourraient en quelque sorte être les mêmes, mais pas toujours j'ai raison? ok alors est-il correct d'utiliser la méthode sans le paramètre car cela me cause une erreur !!
Vert
@ Vert le point est que le nombre d' octets n'est pas toujours le même que le nombre de caractères . Le nombre d' octets dépend du codage de caractères utilisé. Vous devrez savoir quel encodage de caractères vous allez utiliser et en tenir compte. Quelle erreur obtenez vous? Si vous ne faites que l'utiliser, getBytes()il utilisera le codage de caractères par défaut de votre système.
Jesper
1
@KorayTugay Oui, plus ou moins. Vous pourriez cependant discuter de l'ordre de cause à effet. Je serais plus enclin à déclarer qu'un caractère est toujours de 2 octets car il s'agit d'un type de données primitif défini pour être de 2 octets de large. (Et que la représentation UTF-16 était principalement une conséquence de cela, plutôt que l'inverse.)
Andrzej Doyle
63

Si vous utilisez des références 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 d'autres termes:

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

Sur une machine virtuelle 32 bits ou une machine virtuelle 64 bits avec des POO compressés (-XX: + UseCompressedOops), les références sont de 4 octets. Le total serait donc:

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

Cela ne prend pas en compte les références à l'objet string.

roozbeh
la source
6
Je supposais que la question portait sur le nombre d'octets alloués en mémoire pour un objet String. Si la question porte sur le nombre d'octets requis pour sérialiser la chaîne, comme d'autres l'ont souligné, cela dépend du codage utilisé.
roozbeh
2
Source pour votre réponse? Merci
mavis
1
Remarque: sizeofdoit être multiple de 8.
dieter
19

La réponse pédante (mais pas nécessairement la plus utile, selon ce que vous voulez faire du résultat) est:

string.length() * 2

Les chaînes Java sont physiquement stockées dans l' UTF-16BEencodage, qui utilise 2 octets par unité de code, et String.length()mesure la longueur en unités de code UTF-16, donc cela équivaut à:

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

Et cela vous indiquera la taille du chartableau interne , en octets .

Remarque: "UTF-16"donnera un résultat différent de celui "UTF-16BE"que l'ancien encodage insérera une nomenclature , ajoutant 2 octets à la longueur du tableau.

finnw
la source
La réponse de Roozbeh est meilleure, car elle prend également en compte les autres octets.
Lodewijk Bogaards
@finnw Êtes-vous sûr que le codage est UTF-16BE et non UTF-16? Selon la classe Javadoc String ( docs.oracle.com/javase/6/docs/api/java/lang/String.html ), "Une chaîne représente une chaîne au format UTF-16 ...".
entpnerd
17

Selon Comment convertir des chaînes vers et depuis des tableaux d'octets UTF8 en Java :

String s = "some text here";
byte[] b = s.getBytes("UTF-8");
System.out.println(b.length);
Boris Pavlović
la source
mais excusez-moi quand je compile votre code, cela me donne une erreur; à cause du paramètre "UTF-8" .où quand je passe un paramètre vide, il me donne la même longueur que x.length. J'ai mal compris le concept. aide s'il vous plaît
Vert
@Green Ash, quelle version de Java avez-vous?
Buhake Sindi
@Green Ash, quelle exception obtenez-vous?
Buhake Sindi
2
pour être clair, voici la sortie: test.java:11: exception non signalée java.io.UnsupportedEncodingException; doit être intercepté ou déclaré pour être levé byte [] b = s.getBytes ("UTF-8"); ^ 1 erreur Processus terminé.
Vert
3
@Green, essayez: s.getBytes(Charset.forName("UTF-8")).
james.garriss
10

Une Stringinstance alloue une certaine quantité d'octets en mémoire. Peut-être cherchez-vous quelque chose comme sizeof("Hello World")qui retournerait le nombre d'octets alloués par la structure de données elle-même?

En Java, il n'y a généralement pas besoin de sizeoffonction, car nous n'allouons jamais de mémoire pour stocker une structure de données. Nous pouvons jeter un oeil au String.javafichier pour une estimation approximative, et nous voyons des 'int', des références et un char[]. La spécification du langage Java définit que a charva de 0 à 65535, donc deux octets suffisent pour garder un seul caractère en mémoire. Mais une JVM n'a pas besoin de stocker un caractère sur 2 octets, elle doit seulement garantir que l'implémentation de charpeut contenir les valeurs de la plage de définition.

Cela sizeofn'a donc vraiment aucun sens en Java. Mais, en supposant que nous avons une grande chaîne et que l'on charalloue deux octets, alors l'empreinte mémoire d'un Stringobjet est au moins 2 * str.length()en octets.

Andreas Dolk
la source
7

Il existe une méthode appelée getBytes () . Fais-en bon usage .

Andrei Ciobanu
la source
17
Sagement = n'utilisez pas celui sans paramètre de jeu de caractères.
Thilo
Pourquoi? Est-ce un problème si je configure mon environnement pour qu'il s'exécute avec le codage UTF8?
ziggy le
1
getBytes créera et copiera également le tableau d'octets, donc si vous parlez de longues chaînes, cette opération pourrait être coûteuse.
ticktock
@ticktock, si vous êtes toujours là, oui mais quelle est l'alternative? Je suis arrivé ici en espérant qu'une fonction de bibliothèque renvoie le stockage nécessaire afin de pouvoir le combiner dans une allocation plus grande.
SensorSmith
4

Essaye ça :

Bytes.toBytes(x).length

En supposant que vous ayez déclaré et initialisé x avant

fourmi
la source
3
Cela fait-il partie de la bibliothèque Java standard? Je ne trouve pas la Bytesclasse.
Kröw
0

Pour éviter d'essayer d'attraper, utilisez:

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