Converti stringa in array di byte e inverti in Java

1. Introduzione

Abbiamo spesso bisogno di convertire tra String e array di byte in Java. In questo tutorial, esamineremo queste operazioni in dettaglio.

Innanzitutto, esamineremo vari modi per convertire una stringa in un array di byte . Quindi, esamineremo operazioni simili al contrario.

2. Conversione di una stringa in un array di byte

Una stringa viene archiviata come matrice di caratteri Unicode in Java. Per convertirlo in un array di byte , traduciamo la sequenza di caratteri in una sequenza di byte. Per questa traduzione, usiamo un'istanza di Charset . Questa classe specifica una mappatura tra una sequenza di char s e una sequenza di byte di s .

Ci riferiamo al processo di cui sopra come codifica .

Possiamo codificare una stringa in un array di byte in Java in diversi modi. Diamo un'occhiata a ciascuno di essi in dettaglio con esempi.

2.1. Utilizzo di String.getBytes ()

La classe String fornisce tre metodi getBytes sovraccaricati per codificare una stringa in un array di byte :

  • getBytes () - codifica utilizzando il set di caratteri predefinito della piattaforma
  • getBytes (String charsetName) - codifica utilizzando il set di caratteri denominato
  • getBytes (Charset charset) - codifica utilizzando il set di caratteri fornito

Innanzitutto, codifichiamo una stringa utilizzando il set di caratteri predefinito della piattaforma:

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

Il metodo sopra è dipendente dalla piattaforma poiché utilizza il set di caratteri predefinito della piattaforma. Possiamo ottenere questo set di caratteri chiamando Charset.defaultCharset () .

In secondo luogo, codifichiamo una stringa utilizzando un set di caratteri denominato:

@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); }

Questo metodo genera un'eccezione UnsupportedEncodingException se il set di caratteri denominato non è supportato.

Il comportamento delle due versioni precedenti non è definito se l'input contiene caratteri non supportati dal set di caratteri. Al contrario, la terza versione utilizza l'array di byte sostitutivo predefinito del set di caratteri per codificare l'input non supportato.

Successivamente, chiamiamo la terza versione del metodo getBytes () e passiamo un'istanza di 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); }

Qui, stiamo usando il metodo di fabbrica Charset.forName per ottenere un'istanza del Charset . Questo metodo genera un'eccezione di runtime se il nome del set di caratteri richiesto non è valido. Inoltre, genera un'eccezione di runtime se il set di caratteri è supportato nella JVM corrente.

Tuttavia, è garantito che alcuni set di caratteri saranno disponibili su ogni piattaforma Java. La classe StandardCharsets definisce le costanti per questi set di caratteri.

Infine, codifichiamo utilizzando uno dei set di caratteri 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); }

Pertanto, completiamo la revisione delle varie versioni di getBytes . Successivamente, esaminiamo il metodo fornito dallo stesso Charset .

2.2. Utilizzo di Charset.encode ()

La classe Charset fornisce encode () , un metodo conveniente che codifica i caratteri Unicode in byte. Questo metodo sostituisce sempre l'input non valido e i caratteri non mappabili utilizzando l'array di byte di sostituzione predefinito del set di caratteri.

Usiamo il metodo encode per convertire una stringa in un array di byte :

@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); }

Come possiamo vedere sopra, i caratteri non supportati sono stati sostituiti con il byte di sostituzione predefinito 63 del set di caratteri .

Gli approcci utilizzati finora utilizzano internamente la classe CharsetEncoder per eseguire la codifica. Esaminiamo questa classe nella sezione successiva.

2.3. CharsetEncoder

CharsetEncoder trasforma i caratteri Unicode in una sequenza di byte per un determinato set di caratteri . Inoltre, fornisce un controllo dettagliato sul processo di codifica .

Usiamo questa classe per convertire una stringa in un array di byte :

@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

Tutti gli approcci precedenti per la decodifica utilizzano internamente la classe CharsetDecoder . Possiamo usare questa classe direttamente per un controllo dettagliato sul processo di decodifica :

@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); }

Qui, stiamo sostituendo gli input non validi e i caratteri non supportati con "?".

Se vogliamo essere informati in caso di ingressi non validi, possiamo cambiare il decoder come:

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

4. Conclusione

In questo articolo, abbiamo esaminato diversi modi per convertire String in un array di byte e invertire. Dobbiamo scegliere il metodo appropriato in base ai dati di input e al livello di controllo richiesto per gli input non validi.

Come al solito, il codice sorgente completo può essere trovato su GitHub.