155 votes

Transformer un ByteBuffer en String

Est-ce une approche correcte pour convertir un ByteBuffer en String de cette manière ?

String k = "abcd";
ByteBuffer b = ByteBuffer.wrap(k.getBytes());
String v = new String(b.array());

if(k.equals(v))
    System.out.println("it worked");
else
    System.out.println("did not work");

La raison de ma question est que cela semble trop simple, alors que d'autres approches telles que Java : Conversion de String en ByteBuffer et problèmes associés semble plus complexe.

3 votes

Eh bien, tu as essayé ?

6 votes

Oui, je l'ai fait et ça marche. Mais j'ai vu d'autres implémentations plus complexes, telles que stackoverflow.com/questions/1252468/

1 votes

@Doorknob et. al. Il manque l'encodage et son exemple (lorsque la syntaxe sera corrigée) fonctionnera, mais sa méthode n'est toujours pas correcte.

156voto

xinyong Cheng Points 1646

Il existe une approche plus simple pour décoder un ByteBuffer en un String sans aucun problème, mentionné par Andy Thomas.

String s = StandardCharsets.UTF_8.decode(byteBuffer).toString();

6 votes

Sachez qu'UTF-8 n'est peut-être pas le jeu de caractères optimal pour convertir des octets en chaînes de caractères et vice-versa. Pour une correspondance 1 à 1 des octets vers les caractères, il est préférable d'utiliser ISO-8859-1, cf. stackoverflow.com/questions/9098022/ .

2 votes

Aussi, si vous n'avez pas realmente a besoin d'une chaîne de caractères, le CharBuffer decode() retourne est un CharSequence (comme String ), vous pouvez donc éviter une copie supplémentaire et l'utiliser directement.

0 votes

@DavidEhrmann CharBuffer ne possède pas de méthode de décodage - à quoi faites-vous référence ici ?

89voto

Andy Thomas Points 30979

EDIT (2018) : La fratrie éditée La réponse de @xinyongCheng est une approche plus simple, et devrait être la réponse acceptée. .

Votre approche serait raisonnable si vous saviez que les octets sont dans le jeu de caractères par défaut de la plate-forme. Dans votre exemple, cela est vrai car k.getBytes() renvoie les octets dans le jeu de caractères par défaut de la plate-forme.

Plus fréquemment, vous voudrez spécifier l'encodage. Cependant, il existe un moyen plus simple de le faire que la question que vous avez liée. L'API String fournit des méthodes qui permettent de convertir une chaîne en un tableau d'octets[] dans un encodage particulier. Ces méthodes suggèrent d'utiliser CharsetEncoder/CharsetDecoder. "lorsqu'un contrôle accru du processus de décodage [encodage] est nécessaire."

Pour obtenir les octets d'une chaîne dans un codage particulier, vous pouvez utiliser la méthode getBytes() :

byte[] bytes = k.getBytes( StandardCharsets.UTF_8 );

Pour mettre des octets avec un encodage particulier dans une chaîne, vous pouvez utiliser un constructeur de chaîne différent :

String v = new String( bytes, StandardCharsets.UTF_8 );

Notez que ByteBuffer.array() est une opération facultative. Si vous avez construit votre ByteBuffer avec un tableau, vous pouvez utiliser ce tableau directement. Sinon, si vous voulez être sûr, utilisez ByteBuffer.get(byte[] dst, int offset, int length) pour récupérer les octets du tampon dans un tableau d'octets.

0 votes

Et dans le ByteBuffer.get l'entrée est à nouveau un tableau d'octets, comment puis-je l'obtenir ? cela n'a aucun sens de dire à nouveau k.getbytes, n'est-ce pas ?

0 votes

@WilliamKinaan - Vous avez le byte[] que vous avez alimenté en ByteBuffer.get(byte[] dst, int offset, int length) . Vous pouvez construire une chaîne à partir de ce fichier avec le constructeur String() `String(byte[] bytes, int offset, int length, Charset charset). Vous pouvez utiliser les mêmes valeurs de décalage et de longueur pour les deux appels.

1 votes

Il n'y a pas de méthode k.getBytes() dans java.nio.ByteBuffer (peut-être pas dans la version que j'utilise). J'ai donc utilisé la méthode k.array() qui renvoie un byte[].

17voto

Dan Bray Points 576

Essayez ça :

new String(bytebuffer.array(), "ASCII");

NB. Vous ne pouvez pas convertir correctement un tableau d'octets en String sans connaître son encodage.

J'espère que cela vous aidera.

11 votes

UTF-8 est probablement un meilleur choix par défaut que ASCII ?

3 votes

Aucun des deux ne devrait être spécifié, étant donné l'utilisation par le PO de k.getBytes(), qui utilise le jeu de caractères par défaut de la plate-forme.

8 votes

Tous les tampons ne sont pas soutenus par un tableau, donc .array() peut déclencher une exception.

15voto

Fuwjax Points 581

Je voulais juste signaler qu'il n'est pas sûr de supposer que ByteBuffer.array() fonctionnera toujours.

byte[] bytes;
if(buffer.hasArray()) {
    bytes = buffer.array();
} else {
    bytes = new byte[buffer.remaining()];
    buffer.get(bytes);
}
String v = new String(bytes, charset);

En général, buffer.hasArray() sera toujours vrai ou faux, en fonction de votre cas d'utilisation. En pratique, à moins que vous ne vouliez vraiment que cela fonctionne en toutes circonstances, il est prudent d'optimiser la branche dont vous n'avez pas besoin. Mais le reste des réponses peut ne pas fonctionner avec un ByteBuffer qui a été créé par ByteBuffer.allocateDirect().

0 votes

Si le tampon est créé via ByteBuffer.wrap(bytes, offset, size) usine .array() retournera l'intégralité du bytes le tableau. Mieux vaut utiliser la forme suggérée par xinyong Cheng

0 votes

Le .decode() sur Charset est une meilleure solution, je suis d'accord. Je pense que le contexte de ma réponse est une information utile, mais beaucoup moins maintenant.

2 votes

Attention ! Si vous utilisez array() vous doit utiliser également arrayOffset() pour commencer à la bonne position dans le tableau ! C'est un piège subtil, parce que généralement arrayOffset() est égal à 0 ; mais dans les rares cas où ce n'est pas le cas, vous obtiendrez des bogues difficiles à trouver si vous ne le prenez pas en compte.

8voto

alexwriteshere Points 3849

Les réponses se référant à un simple appel array() ne sont pas tout à fait correctes : lorsque le tampon a été partiellement consommé, ou se réfère à une partie d'un tableau (on peut ByteBuffer.wrap un tableau à un décalage donné, pas nécessairement depuis le début), nous devons en tenir compte dans nos calculs. C'est la solution générale qui fonctionne pour les tampons dans tous les cas (elle ne couvre pas l'encodage) :

if (myByteBuffer.hasArray()) {
    return new String(myByteBuffer.array(),
        myByteBuffer.arrayOffset() + myByteBuffer.position(),
        myByteBuffer.remaining());
} else {
    final byte[] b = new byte[myByteBuffer.remaining()];
    myByteBuffer.duplicate().get(b);
    return new String(b);
}

Pour les préoccupations liées à l'encodage, voir la réponse d'Andy Thomas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X