Me gustaría convertir una matriz de caracteres en una matriz de bytes en Java. ¿Qué métodos existen para realizar esta conversión?
Me gustaría convertir una matriz de caracteres en una matriz de bytes en Java. ¿Qué métodos existen para realizar esta conversión?
Respuestas:
char[] ch = ?
new String(ch).getBytes();
o
new String(ch).getBytes("UTF-8");
para obtener un juego de caracteres no predeterminado.
Actualización: desde Java 7:new String(ch).getBytes(StandardCharsets.UTF_8);
Convertir sin crear Stringobjeto:
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;
}
Uso:
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 solución está inspirada en la recomendación de Swing para almacenar contraseñas en char []. (Consulte ¿Por qué se prefiere char [] sobre String para las contraseñas? )
Recuerde no escribir datos confidenciales en los registros y asegúrese de que JVM no contenga referencias a ellos.
El código anterior es correcto pero no efectivo. Si no necesita rendimiento pero desea seguridad, puede usarlo. Si la seguridad tampoco es un objetivo, hágalo simplemente String.getBytes. El código anterior no es efectivo si observa la implementación de encodeen JDK. Además, necesita copiar matrices y crear búferes. Otra forma de convertir es en línea todo el código subyacente encode(ejemplo para 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"))
Disculpe por usar el lenguaje Scala. Si tiene problemas para convertir este código a Java, puedo reescribirlo. ¿Qué pasa con el rendimiento? Siempre verifique los datos reales (con JMH, por ejemplo). Este código es muy similar a lo que puede ver en JDK [ 2 ] y Protobuf [ 3 ].
La respuesta de Andrey (la más votada en el momento de escribir este artículo) es ligeramente incorrecta. Hubiera agregado esto como comentario, pero no soy lo suficientemente confiable.
En la respuesta de Andrey:
char[] chars = {'c', 'h', 'a', 'r', 's'}
byte[] bytes = Charset.forName("UTF-8").encode(CharBuffer.wrap(chars)).array();
la llamada a array () puede no devolver el valor deseado, por ejemplo:
char[] c = "aaaaaaaaaa".toCharArray();
System.out.println(Arrays.toString(Charset.forName("UTF-8").encode(CharBuffer.wrap(c)).array()));
salida:
[97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 0]
Como puede verse, se ha añadido un byte cero. Para evitar esto, utilice lo siguiente:
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));
salida:
[97, 97, 97, 97, 97, 97, 97, 97, 97, 97]
Como la respuesta también aludía al uso de contraseñas, podría valer la pena borrar la matriz que respalda el ByteBuffer (a la que se accede a través de la función 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));
averageBytesPerChar()devuelve algo distinto de 1 (obtengo 1.1). Por interés, ¿qué sistema operativo / arch está usando? Verifiqué dos veces con Oracle 1.7.0_51 y openjdk 1.7.0_51 y lo encontré roto con 10 caracteres.
buffer.array()en cuenta que en la toBytesfunción aún debe anularse, actualmente solo la copia es.
Podrías hacer un método:
public byte[] toBytes(char[] data) {
byte[] toRet = new byte[data.length];
for(int i = 0; i < toRet.length; i++) {
toRet[i] = (byte) data[i];
}
return toRet;
}
Espero que esto ayude