Me gustaría convertir una matriz de caracteres en una matriz de bytes en Java. ¿Qué métodos existen para realizar esta conversión?
java
arrays
type-conversion
Arun Abraham
fuente
fuente
Convertir sin crear
String
objeto: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 deencode
en JDK. Además, necesita copiar matrices y crear búferes. Otra forma de convertir es en línea todo el código subyacenteencode
(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 ].
fuente
Editar: la respuesta de Andrey se ha actualizado, por lo que lo siguiente ya no se aplica.
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));
fuente
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 latoBytes
función aún debe anularse, actualmente solo la copia es.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; }
fuente
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
fuente