Je voudrais convertir un tableau de caractères en un tableau d'octets en Java. Quelles méthodes existent pour effectuer cette conversion?
char[] ch = ?
new String(ch).getBytes();
ou
new String(ch).getBytes("UTF-8");
pour obtenir un jeu de caractères autre que celui par défaut.
Mise à jour: Depuis Java 7: new String(ch).getBytes(StandardCharsets.UTF_8);
Convertir sans créer l'objet String
:
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;
}
Usage:
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
La solution s'inspire de la recommandation Swing pour stocker les mots de passe dans char []. (Voir Pourquoi char [] est-il préféré à String pour les mots de passe? )
N'oubliez pas de ne pas écrire de données sensibles dans les journaux et de vous assurer que JVM ne contiendra aucune référence à ces données.
Le code ci-dessus est correct mais pas efficace. Si vous n'avez pas besoin de performance mais que vous voulez de la sécurité, vous pouvez l'utiliser. Si la sécurité n’est pas non plus un objectif, faites simplement String.getBytes
. Le code ci-dessus n'est pas efficace si vous négligez l'implémentation de encode
dans JDK. En outre, vous devez copier des tableaux et créer des tampons. Un autre moyen de convertir le code en ligne derrière encode
(exemple pour 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"))
Excusez-moi d'utiliser le langage Scala. Si vous rencontrez des problèmes pour convertir ce code en Java, je peux le réécrire. Qu'en est-il des performances toujours vérifier sur des données réelles (avec JMH par exemple). Ce code est très similaire à ce que vous pouvez voir dans JDK [ 2 ] et Protobuf [ 3 ].
La réponse d'Andrey (le plus voté au moment de la rédaction) est légèrement incorrecte. J'aurais ajouté ceci comme commentaire mais je ne suis pas assez fiable.
Dans la réponse de Andreï:
char[] chars = {'c', 'h', 'a', 'r', 's'}
byte[] bytes = Charset.forName("UTF-8").encode(CharBuffer.wrap(chars)).array();
l'appel à array () peut ne pas renvoyer la valeur souhaitée, par exemple:
char[] c = "aaaaaaaaaa".toCharArray();
System.out.println(Arrays.toString(Charset.forName("UTF-8").encode(CharBuffer.wrap(c)).array()));
sortie:
[97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 0]
Comme on peut le constater, un octet zéro a été ajouté. Pour éviter cela, utilisez ce qui suit:
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));
sortie:
[97, 97, 97, 97, 97, 97, 97, 97, 97, 97]
Comme la réponse faisait également allusion à l’utilisation de mots de passe, il pourrait être utile de supprimer le tableau qui sauvegarde le ByteBuffer (accessible via la fonction 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));
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;
}