Convertir une chaîne en tableau d'octets et inverser en Java

1. Introduction

Nous avons souvent besoin de convertir entre String et tableau d' octets en Java. Dans ce didacticiel, nous examinerons ces opérations en détail.

Tout d'abord, nous examinerons différentes manières de convertir une chaîne en un tableau d' octets . Ensuite, nous examinerons des opérations similaires en sens inverse.

2. Conversion d'une chaîne en tableau d' octets

Une chaîne est stockée sous la forme d'un tableau de caractères Unicode en Java. Pour le convertir en un tableau d' octets , nous traduisons la séquence de caractères en une séquence d'octets. Pour cette traduction, nous utilisons une instance de Charset . Cette classe spécifie une mise en correspondance entre une séquence de carbonisation s et une séquence d' octets s .

Nous nous référons au processus ci-dessus en tant que codage .

Nous pouvons encoder une chaîne dans un tableau d' octets en Java de plusieurs manières. Regardons chacun d'eux en détail avec des exemples.

2.1. Utilisation de String.getBytes ()

La classe String fournit trois méthodes getBytes surchargées pour encoder une chaîne dans un tableau d' octets :

  • getBytes () - encode en utilisant le jeu de caractères par défaut de la plateforme
  • getBytes (String charsetName) - encode à l'aide du jeu de caractères nommé
  • getBytes (Charset charset) - encode en utilisant le charset fourni

Tout d'abord, encodons une chaîne en utilisant le jeu de caractères par défaut de la plateforme:

String inputString = "Hello World!"; byte[] byteArrray = inputString.getBytes();

La méthode ci-dessus dépend de la plate-forme car elle utilise le jeu de caractères par défaut de la plate-forme. Nous pouvons obtenir ce jeu de caractères en appelant Charset.defaultCharset () .

Deuxièmement, encodons une chaîne à l'aide d'un jeu de caractères nommé:

@Test public void whenGetBytesWithNamedCharset_thenOK() throws UnsupportedEncodingException { String inputString = "Hello World!"; String charsetName = "IBM01140"; byte[] byteArrray = inputString.getBytes("IBM01140"); assertArrayEquals( new byte[] { -56, -123, -109, -109, -106, 64, -26, -106, -103, -109, -124, 90 }, byteArrray); }

Cette méthode lève une exception UnsupportedEncodingException si le jeu de caractères nommé n'est pas pris en charge.

Le comportement des deux versions ci-dessus n'est pas défini si l'entrée contient des caractères qui ne sont pas pris en charge par le jeu de caractères. En revanche, la troisième version utilise le tableau d'octets de remplacement par défaut du jeu de caractères pour coder une entrée non prise en charge.

Ensuite, appelons la troisième version de la méthode getBytes () et passons une instance de Charset:

@Test public void whenGetBytesWithCharset_thenOK() { String inputString = "Hello ਸੰਸਾਰ!"; Charset charset = Charset.forName("ASCII"); byte[] byteArrray = inputString.getBytes(charset); assertArrayEquals( new byte[] { 72, 101, 108, 108, 111, 32, 63, 63, 63, 63, 63, 33 }, byteArrray); }

Ici, nous utilisons la méthode d'usine Charset.forName pour obtenir une instance du Charset . Cette méthode lève une exception d'exécution si le nom du jeu de caractères demandé n'est pas valide. Il lève également une exception d'exécution si le jeu de caractères est pris en charge dans la JVM actuelle.

Cependant, certains jeux de caractères sont garantis disponibles sur toutes les plates-formes Java. La classe StandardCharsets définit des constantes pour ces jeux de caractères.

Enfin, encodons en utilisant l'un des jeux de caractères standard:

@Test public void whenGetBytesWithStandardCharset_thenOK() { String inputString = "Hello World!"; Charset charset = StandardCharsets.UTF_16; byte[] byteArrray = inputString.getBytes(charset); assertArrayEquals( new byte[] { -2, -1, 0, 72, 0, 101, 0, 108, 0, 108, 0, 111, 0, 32, 0, 87, 0, 111, 0, 114, 0, 108, 0, 100, 0, 33 }, byteArrray); }

Ainsi, nous terminons la revue des différentes versions de getBytes . Ensuite, regardons la méthode fournie par Charset lui-même.

2.2. Utilisation de Charset.encode ()

La classe Charset fournit encode () , une méthode pratique qui encode les caractères Unicode en octets. Cette méthode remplace toujours les entrées non valides et les caractères non mappables à l'aide du tableau d'octets de remplacement par défaut du jeu de caractères.

Utilisons la méthode d' encode pour convertir une chaîne en un tableau d' octets :

@Test public void whenEncodeWithCharset_thenOK() { String inputString = "Hello ਸੰਸਾਰ!"; Charset charset = StandardCharsets.US_ASCII; byte[] byteArrray = charset.encode(inputString).array(); assertArrayEquals( new byte[] { 72, 101, 108, 108, 111, 32, 63, 63, 63, 63, 63, 33 }, byteArrray); }

Comme nous pouvons le voir ci-dessus, les caractères non pris en charge ont été remplacés par l' octet de remplacement par défaut 63 du jeu de caractères .

Les approches utilisées jusqu'à présent utilisent la classe CharsetEncoder en interne pour effectuer le codage. Examinons cette classe dans la section suivante.

2.3. CharsetEncoder

CharsetEncoder transforme les caractères Unicode en une séquence d'octets pour un jeu de caractères donné . De plus, il offre un contrôle précis du processus de codage .

Utilisons cette classe pour convertir une chaîne en un tableau d' octets :

@Test public void whenUsingCharsetEncoder_thenOK() throws CharacterCodingException { String inputString = "Hello ਸੰਸਾਰ!"; CharsetEncoder encoder = StandardCharsets.US_ASCII.newEncoder(); encoder.onMalformedInput(CodingErrorAction.IGNORE) .onUnmappableCharacter(CodingErrorAction.REPLACE) .replaceWith(new byte[] { 0 }); byte[] byteArrray = encoder.encode(CharBuffer.wrap(inputString)) .array(); assertArrayEquals( new byte[] { 72, 101, 108, 108, 111, 32, 0, 0, 0, 0, 0, 33 }, byteArrray); }

Here, we're creating an instance of CharsetEncoder by calling the newEncoder method on a Charset object.

Then, we are specifying actions for error conditions by calling the onMalformedInput() and onUnmappableCharacter() methods. We can specify the following actions:

  • IGNORE – drop the erroneous input
  • REPLACE – replace the erroneous input
  • REPORT – report the error by returning a CoderResult object or throwing a CharacterCodingException

Furthermore, we are using the replaceWith() method to specify the replacement byte array .

Thus, we complete the review of various approaches to convert a String to a byte array. Let's next look at the reverse operation.

3. Converting Byte Array to String

We refer to the process of converting a byte array to a String as decoding. Similar to encoding, this process requires a Charset.

However, we cannot just use any charset for decoding a byte array. We should use the charset that was used to encode the String into the byte array.

We can convert a byte array to a String in many ways. Let's examine each of them in detail.

3.1. Using the String Constructor

The String class has few constructors which take a byte array as input. They are all similar to the getBytes method but work in reverse.

First, let's convert a byte array to String using the platform's default charset:

@Test public void whenStringConstructorWithDefaultCharset_thenOK() { byte[] byteArrray = { 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33 }; String string = new String(byteArrray); assertNotNull(string); }

Note that we don't assert anything here about the contents of the decoded string. This is because it may decode to something different, depending on the platform's default charset.

For this reason, we should generally avoid this method.

Secondly, let's use a named charset for decoding:

@Test public void whenStringConstructorWithNamedCharset_thenOK() throws UnsupportedEncodingException { String charsetName = "IBM01140"; byte[] byteArrray = { -56, -123, -109, -109, -106, 64, -26, -106, -103, -109, -124, 90 }; String string = new String(byteArrray, charsetName); assertEquals("Hello World!", string); }

This method throws an exception if the named charset is not available on the JVM.

Thirdly, let's use a Charset object to do decoding:

@Test public void whenStringConstructorWithCharSet_thenOK() { Charset charset = Charset.forName("UTF-8"); byte[] byteArrray = { 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33 }; String string = new String(byteArrray, charset); assertEquals("Hello World!", string); }

Finally, let's use a standard Charset for the same:

@Test public void whenStringConstructorWithStandardCharSet_thenOK() { Charset charset = StandardCharsets.UTF_16; byte[] byteArrray = { -2, -1, 0, 72, 0, 101, 0, 108, 0, 108, 0, 111, 0, 32, 0, 87, 0, 111, 0, 114, 0, 108, 0, 100, 0, 33 }; String string = new String(byteArrray, charset); assertEquals("Hello World!", string); }

So far, we have converted a byte array into a String using the constructor. Let's now look into the other approaches.

3.2. Using Charset.decode()

The Charset class provides the decode() method that converts a ByteBuffer to String:

@Test public void whenDecodeWithCharset_thenOK() { byte[] byteArrray = { 72, 101, 108, 108, 111, 32, -10, 111, 114, 108, -63, 33 }; Charset charset = StandardCharsets.US_ASCII; String string = charset.decode(ByteBuffer.wrap(byteArrray)) .toString(); assertEquals("Hello �orl�!", string); }

Here, the invalid input is replaced with the default replacement character for the charset.

3.3. CharsetDecoder

Toutes les approches précédentes de décodage utilisent en interne la classe CharsetDecoder . Nous pouvons utiliser cette classe directement pour un contrôle fin sur le processus de décodage :

@Test public void whenUsingCharsetDecoder_thenOK() throws CharacterCodingException { byte[] byteArrray = { 72, 101, 108, 108, 111, 32, -10, 111, 114, 108, -63, 33 }; CharsetDecoder decoder = StandardCharsets.US_ASCII.newDecoder(); decoder.onMalformedInput(CodingErrorAction.REPLACE) .onUnmappableCharacter(CodingErrorAction.REPLACE) .replaceWith("?"); String string = decoder.decode(ByteBuffer.wrap(byteArrray)) .toString(); assertEquals("Hello ?orl?!", string); }

Ici, nous remplaçons les entrées invalides et les caractères non pris en charge par «?».

Si nous voulons être informés en cas d'entrées invalides, nous pouvons changer le décodeur comme:

decoder.onMalformedInput(CodingErrorAction.REPORT) .onUnmappableCharacter(CodingErrorAction.REPORT)

4. Conclusion

Dans cet article, nous avons étudié plusieurs façons de convertir String en tableau d'octets et de l'inverser. Nous devons choisir la méthode appropriée en fonction des données d'entrée ainsi que du niveau de contrôle requis pour les entrées invalides.

Comme d'habitude, le code source complet peut être trouvé sur GitHub.