wake-up-neo.com

Char [] in Byte [] konvertieren

Ich möchte ein Zeichen-Array in ein Byte-Array in Java konvertieren. Welche Methoden gibt es für diese Konvertierung?

68
Arun Abraham
char[] ch = ?
new String(ch).getBytes();

oder

new String(ch).getBytes("UTF-8");

um einen nicht standardmäßigen Zeichensatz zu erhalten.

Update: Seit Java 7: new String(ch).getBytes(StandardCharsets.UTF_8);

68
Tarlog

Konvertieren ohne String-Objekt zu erstellen:

import Java.nio.CharBuffer;
import Java.nio.ByteBuffer;
import Java.util.Arrays;

byte[] toBytes(char[] chars) {
  CharBuffer charBuffer = CharBuffer.wrap(chars);
  ByteBuffer byteBuffer = Charset.forName("UTF-8").encode(charBuffer);
  byte[] bytes = Arrays.copyOfRange(byteBuffer.array(),
            byteBuffer.position(), byteBuffer.limit());
  Arrays.fill(byteBuffer.array(), (byte) 0); // clear sensitive data
  return bytes;
}

Verwendungszweck:

char[] chars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
byte[] bytes = toBytes(chars);
/* do something with chars/bytes */
Arrays.fill(chars, '\u0000'); // clear sensitive data
Arrays.fill(bytes, (byte) 0); // clear sensitive data

Die Lösung basiert auf der Swing-Empfehlung zum Speichern von Kennwörtern in char []. (Siehe Warum wird char [] String für Kennwörter vorgezogen? )

Denken Sie daran, keine sensiblen Daten in die Protokolle zu schreiben, und stellen Sie sicher, dass die JVM keine Verweise darauf enthält.


Der obige Code ist korrekt, aber nicht effektiv. Wenn Sie keine Leistung benötigen, aber Sicherheit wünschen, können Sie sie verwenden. Wenn Sicherheit auch kein Ziel ist, dann String.getBytes. Code oben ist nicht wirksam, wenn Sie von der Implementierung von encode in JDK nach unten schauen. Außerdem müssen Sie Arrays kopieren und Puffer erstellen. Eine andere Möglichkeit zum Konvertieren ist der Inline-Code für encode (Beispiel für UTF-8)

val xs: Array[Char] = "A ß € 嗨 ???? ????".toArray
val len = xs.length
val ys: Array[Byte] = new Array(3 * len) // worst case
var i = 0; var j = 0 // i for chars; j for bytes
while (i < len) { // fill ys with bytes
  val c = xs(i)
  if (c < 0x80) {
    ys(j) = c.toByte
    i = i + 1
    j = j + 1
  } else if (c < 0x800) {
    ys(j) = (0xc0 | (c >> 6)).toByte
    ys(j + 1) = (0x80 | (c & 0x3f)).toByte
    i = i + 1
    j = j + 2
  } else if (Character.isHighSurrogate(c)) {
    if (len - i < 2) throw new Exception("overflow")
    val d = xs(i + 1)
    val uc: Int = 
      if (Character.isLowSurrogate(d)) {
        Character.toCodePoint(c, d)
      } else {
        throw new Exception("malformed")
      }
    ys(j) = (0xf0 | ((uc >> 18))).toByte
    ys(j + 1) = (0x80 | ((uc >> 12) & 0x3f)).toByte
    ys(j + 2) = (0x80 | ((uc >>  6) & 0x3f)).toByte
    ys(j + 3) = (0x80 | (uc & 0x3f)).toByte
    i = i + 2 // 2 chars
    j = j + 4
  } else if (Character.isLowSurrogate(c)) {
    throw new Exception("malformed")
  } else {
    ys(j) = (0xe0 | (c >> 12)).toByte
    ys(j + 1) = (0x80 | ((c >> 6) & 0x3f)).toByte
    ys(j + 2) = (0x80 | (c & 0x3f)).toByte
    i = i + 1
    j = j + 3
  }
}
// check
println(new String(ys, 0, j, "UTF-8"))

Entschuldigen Sie, dass Sie Scala-Sprache verwenden. Wenn Sie Probleme bei der Konvertierung dieses Codes in Java haben, kann ich ihn umschreiben. Was ist mit der Leistung? Überprüfen Sie immer auf realen Daten (zum Beispiel mit JMH). Dieser Code sieht sehr ähnlich aus wie in JDK [ 2 ] und Protobuf [ 3 ].

140
Nobody Tells

Bearbeiten: Die Antwort von Andrey wurde aktualisiert, sodass das Folgende nicht mehr gilt.

Die Antwort von Andrey (die höchste Stimme zum Zeitpunkt des Schreibens) ist leicht falsch. Ich hätte dies als Kommentar hinzugefügt, aber ich bin nicht seriös genug.

In der Antwort von Andrey:

char[] chars = {'c', 'h', 'a', 'r', 's'}
byte[] bytes = Charset.forName("UTF-8").encode(CharBuffer.wrap(chars)).array();

der Aufruf von array () gibt möglicherweise nicht den gewünschten Wert zurück. Beispiel:

char[] c = "aaaaaaaaaa".toCharArray();
System.out.println(Arrays.toString(Charset.forName("UTF-8").encode(CharBuffer.wrap(c)).array()));

ausgabe:

[97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 0]

Wie zu sehen ist, wurde ein Null-Byte hinzugefügt. Um dies zu vermeiden, verwenden Sie Folgendes:

char[] c = "aaaaaaaaaa".toCharArray();
ByteBuffer bb = Charset.forName("UTF-8").encode(CharBuffer.wrap(c));
byte[] b = new byte[bb.remaining()];
bb.get(b);
System.out.println(Arrays.toString(b));

ausgabe:

[97, 97, 97, 97, 97, 97, 97, 97, 97, 97]

Da die Antwort auch auf die Verwendung von Kennwörtern anspielt, kann es sich lohnen, Das Array auszublenden, das den ByteBuffer unterstützt (Zugriff über die Funktion Array ()):

ByteBuffer bb = Charset.forName("UTF-8").encode(CharBuffer.wrap(c));
byte[] b = new byte[bb.remaining()];
bb.get(b);
blankOutByteArray(bb.array());
System.out.println(Arrays.toString(b));
17
djsutho
private static byte[] charArrayToByteArray(char[] c_array) {
        byte[] b_array = new byte[c_array.length];
        for(int i= 0; i < c_array.length; i++) {
            b_array[i] = (byte)(0xFF & (int)c_array[i]);
        }
        return b_array;
}
0
Matt