Java: Utilizando el tipo de juego de palabras en matrices primitivas?
-
20-09-2019 - |
Pregunta
Tengo que ser capaz de convertir matrices de bytes a / desde otras matrices de tipo primitivo, pero en lugar de fundición, necesito tipo juegos de palabras . término correcto para la copia en bruto sin poner?
pensé que sería posible hacer lo siguiente:
// idea: byte[12] -> int[3], and int[3] -> byte[12]
int[] ints;
ByteBuffer bb = ByteBuffer.wrap(
new byte[]{ 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3 });
IntBuffer ib = bb.asIntBuffer();
ints = ib.array(); // java.lang.UnsupportedOperationException
ints = ib.duplicate().array(); // java.lang.UnsupportedOperationException
Por desgracia, parece que es bb.asIntBuffer()
no crear una nueva IntBuffer copiando el contenido de "bit a bit" o "en bruto", sino que crea una nueva "visión" en la ByteBuffer existente. Es por eso que .array()
está destinado al fracaso.
I navegado alrededor de las fuentes de JDK, y encontraron pocas clases, que son utilizados por todas estas clases de amortiguación y gustaría hacer las cosas que necesito, pero son internos (como el Unsafe
clase).
Si bien creo que mi objetivo podría lograrse envolviendo la memoria intermedia de bytes de alguna ObjectInputStream
y leer los valores primitivos de .readInt()
, creo que sería una solución desordenado y lento.
Así que, ¿hay otras soluciones posibles sin haciendo aritmética tipo primitivo mágicos (cambiantes, comprobando endians, ...)?
NOTA: Necesito ambas direcciones: byte [12] -> int [3], y int [3] -> byte [12]
Solución
Según el javadoc, array () [1] devuelve array respaldo de la memoria intermedia, que es la matriz que especifica con la llamada para envolver () [2].
Por lo tanto, es necesario crear una nueva matriz con el tipo deseado. Pero la aritmética aún pueden ser manejados a través de las clases de amortiguamiento.
ByteBuffer bb = ByteBuffer.wrap(new byte[]{ 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3 });
IntBuffer ib = bb.asIntBuffer();
int[] intArray = new int[ib.limit()];
ib.get(intArray);
Al revés requiere un poco de cálculo por sí mismo.
ByteBuffer newBb = ByteBuffer.allocate(intArray.length*4);
newBb.asIntBuffer().put(intArray);
byte[] byteArray = newBb.array();
Ver:
[1] http://java.sun.com/javase/6/docs/api/java/nio/ByteBuffer.html#array%28%29
[2] http://java.sun.com/javase/6/docs/api/java/nio/ByteBuffer.html#wrap%28byte []% 29
Otros consejos
Muchas gracias a wierob por su código para la conversión de byte [] -> int []
He jugado un poco para obtener la dirección opuesta de trabajo.
1) API
// byte[] -> int[]
public static int[] punnedToInteger(byte[] in){
ByteBuffer bb = ByteBuffer.wrap(in);
IntBuffer pb = bb.asIntBuffer();
int[] out = new int[pb.limit()];
pb.get(out);
return out;
}
// int[] -> byte[]
public static byte[] punnedFromInteger(int[] in){
byte[] out = new byte[in.length * Integer.SIZE / Byte.SIZE];
ByteBuffer bb = ByteBuffer.wrap(out);
for(int i=0; i<in.length; ++i){
bb.putInt(in[i]);
}
return out;
}
2) Caso de prueba
{
byte[] bytes = new byte[]{ 0,0,0,1, 0,0,1,0, 0,1,0,0, 1,0,0,0 };
int[] ints = punnedToInteger(bytes);
System.out.println(Arrays.toString(bytes));
System.out.println(Arrays.toString(ints));
System.out.println();
}
{
int[] ints = new int[]{ 1, 256, 65536, 16777216 };
byte[] bytes = punnedFromInteger(ints);
System.out.println(Arrays.toString(ints));
System.out.println(Arrays.toString(bytes));
System.out.println();
}
3) de salida
[0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0]
[1, 256, 65536, 16777216]
[1, 256, 65536, 16777216]
[0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0]