HOWTO · Java
Convertir matriz de bytes a entero en Java
Este tutorial demuestra cómo convertir un array de bytes a int en Java
En esta página
Convertir un array de bytes en un entero en Java es una tarea habitual al trabajar con protocolos de red, E/S de archivos o formatos de datos binarios. El enfoque adecuado depende de lo que representen los bytes: a veces varios bytes codifican un único int y otras veces cada byte es un valor independiente. Este artículo explica los métodos principales de Java — ByteBuffer, DataInputStream, el desplazamiento manual de bits y BigInteger — además de las reglas de orden de bytes y signo que determinan si el resultado es correcto.
Convertir cuatro bytes en un int con ByteBuffer
ByteBuffer (en java.nio) es la herramienta más directa del núcleo de Java para esta conversión. El método wrap crea un búfer que comparte el almacenamiento del array, y getInt() lee cuatro bytes a partir de la posición actual del búfer y los interpreta como un único int. Ejecuta este ejemplo (el código y el mensaje que imprime permanecen en inglés):
import java.nio.ByteBuffer;
public class ByteArrayToInt {
public static void main(String[] args) {
byte[] byteArray = {0x00, 0x01, 0x03, 0x10};
int intValue = ByteBuffer.wrap(byteArray).getInt();
System.out.println("Converted Integer Value: " + intValue);
}
}
Salida:
Converted Integer Value: 66320
Un ByteBuffer es big-endian de forma predeterminada en todas las plataformas: el primer byte del array se trata como el byte más significativo. Si los datos se escribieron en orden little-endian, selecciona ese orden explícitamente con ByteOrder antes de leerlos (las etiquetas del ejemplo permanecen en inglés):
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class ByteArrayToIntOrder {
public static void main(String[] args) {
byte[] byteArray = {0x00, 0x01, 0x03, 0x10};
int bigEndianValue = ByteBuffer.wrap(byteArray).getInt();
int littleEndianValue =
ByteBuffer.wrap(byteArray).order(ByteOrder.LITTLE_ENDIAN).getInt();
System.out.println("big-endian: " + bigEndianValue);
System.out.println("little-endian: " + littleEndianValue);
}
}
Salida:
big-endian: 66320
little-endian: 268632320
Aquí importan dos detalles. En primer lugar, getInt() lee desde la posición actual del búfer y la avanza en cuatro, por lo que llamarlo dos veces sobre el mismo búfer lee los cuatro bytes siguientes; un wrap nuevo siempre comienza en la posición 0. En segundo lugar, cuando quedan menos de cuatro bytes, getInt() lanza una BufferUnderflowException, así que comprueba la longitud de la entrada antes de leer.
Leer cuatro bytes con DataInputStream
Cuando los bytes llegan a través de un flujo —o cuando quieres leer varios valores primitivos en secuencia— DataInputStream es una buena opción. Envuelve el array en un ByteArrayInputStream, envuélvelo a su vez en un DataInputStream y llama a readInt() (el código y el mensaje que imprime permanecen en inglés):
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
public class ByteArrayToIntWithDataInputStream {
public static void main(String[] args) throws IOException {
byte[] byteArray = {0x00, 0x01, 0x03, 0x10};
try (DataInputStream input =
new DataInputStream(new ByteArrayInputStream(byteArray))) {
int intValue = input.readInt();
System.out.println("Converted Integer Value: " + intValue);
}
}
}
Salida:
Converted Integer Value: 66320
readInt() siempre interpreta los cuatro bytes siguientes en orden big-endian, independientemente de la plataforma. Cuando quedan menos de cuatro bytes en el flujo, lanza una EOFException, que puedes capturar para informar de una entrada incompleta en lugar de que el programa falle (el ejemplo y su mensaje permanecen en inglés):
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
public class ByteArrayToIntShortInput {
public static void main(String[] args) throws IOException {
byte[] byteArray = {0x03, 0x10};
try (DataInputStream input =
new DataInputStream(new ByteArrayInputStream(byteArray))) {
int intValue = input.readInt();
System.out.println("Converted Integer Value: " + intValue);
} catch (EOFException e) {
System.out.println("readInt() needs four bytes, but only " + byteArray.length + " remain");
}
}
}
Salida:
readInt() needs four bytes, but only 2 remain
Construir un int desplazando bytes
Desplazar los bytes manualmente muestra exactamente cómo funciona la conversión y ofrece control total sobre el orden y la longitud. Para cada byte, desplaza el valor acumulado 8 bits a la izquierda y combínalo con el byte siguiente mediante OR (el código y el mensaje que imprime permanecen en inglés):
public class ByteArrayToIntManually {
public static void main(String[] args) {
byte[] byteArray = {0x00, 0x01, 0x03, 0x10};
int intValue = 0;
for (byte b : byteArray) {
intValue = (intValue << 8) | (b & 0xFF);
}
System.out.println("Converted Integer Value: " + intValue);
}
}
Salida:
Converted Integer Value: 66320
La máscara b & 0xFF es necesaria porque el tipo byte de Java tiene signo: 0x80 se almacena como -128. Sin la máscara, | combinaría 0xFFFFFF80 en lugar de 0x00000080, lo que corrompería todos los bytes superiores. Este bucle ensambla los bytes en orden big-endian —el primer elemento del array es el byte más significativo— y supone que el array contiene exactamente cuatro bytes. Para usar otro orden, recorre el array en dirección opuesta; para más bytes, acumula en un long en lugar de un int.
Interpretar un array de bytes con BigInteger
BigInteger acepta un array de bytes directamente en su constructor y lo interpreta como un número con signo, big-endian y en complemento a dos, de longitud arbitraria. Después, intValue() reduce el resultado a un int (el código y el mensaje que imprime permanecen en inglés):
import java.math.BigInteger;
public class ByteArrayToIntWithBigInteger {
public static void main(String[] args) {
byte[] byteArray = {0x00, 0x01, 0x03, 0x10};
int intValue = new BigInteger(byteArray).intValue();
System.out.println("Converted Integer Value: " + intValue);
}
}
Salida:
Converted Integer Value: 66320
Como la interpretación tiene signo, un bit inicial 1 produce un valor inferior a 0; pasa un signum de 1 como primer argumento del constructor para obtener la interpretación sin signo. Ten en cuenta que intValue() conserva únicamente los 32 bits inferiores, por lo que trunca silenciosamente los valores que no caben en un int (las etiquetas del ejemplo permanecen en inglés):
import java.math.BigInteger;
public class BigIntegerSignAndRange {
public static void main(String[] args) {
byte[] allOnes = {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF};
System.out.println("signed: " + new BigInteger(allOnes));
System.out.println("unsigned: " + new BigInteger(1, allOnes));
System.out.println("narrowed to int: " + new BigInteger(1, allOnes).intValue());
}
}
Salida:
signed: -1
unsigned: 4294967295
narrowed to int: -1
BigInteger es la opción natural cuando el array tiene más de cuatro bytes o cuando necesitas la magnitud sin signo antes de reducirla.
Convertir cada byte por separado
Todos los métodos anteriores combinan varios bytes en un único número. Si cada byte es un valor independiente —lecturas de sensores, canales de color o campos de protocolo— convierte los elementos individualmente. Observa la diferencia: getShort() o readShort() sobre dos bytes produce un único short combinado; no convierte cada byte por separado.
Recuerda también que el tipo byte de Java tiene signo y va de -128 a 127. Cuando lo que necesitas es un valor sin signo de 0 a 255, usa Byte.toUnsignedInt (disponible desde Java 8) o la máscara equivalente b & 0xFF (las etiquetas del ejemplo permanecen en inglés):
public class PrintEachByte {
public static void main(String[] args) {
byte[] byteArray = {0x03, 0x04, (byte) 0x80, (byte) 0xFF};
for (byte b : byteArray) {
System.out.println("signed: " + b + " unsigned: " + Byte.toUnsignedInt(b));
}
}
}
Salida:
signed: 3 unsigned: 3
signed: 4 unsigned: 4
signed: -128 unsigned: 128
signed: -1 unsigned: 255
Elegir un método y gestionar casos límite
Cada enfoque se adapta a una situación distinta:
ByteBufferes la primera opción para leer unintde cuatro bytes desde un array: es compacto, admite ambos órdenes de bytes medianteByteOrdery proporcionagetLong(),getShort()y métodos similares para otros tamaños.DataInputStreamresulta adecuado para código que ya trabaja con flujos y necesita leer varios valores con tipo en secuencia; sus lecturas siempre son big-endian.- El desplazamiento manual requiere algunas líneas más, pero controla con precisión el orden, el desplazamiento inicial y el tamaño, sin necesidad de crear un búfer ni un flujo.
BigIntegergestiona arrays de más de cuatro bytes y permite una interpretación explícita con o sin signo antes de reducir el valor.- La conversión byte a byte con
Byte.toUnsignedIntse aplica cuando cada elemento es un valor propio y no parte de un único número.
Elijas el método que elijas, comprueba estos puntos antes de convertir:
- Longitud de la entrada: una lectura de cuatro bytes sobre un array más corto falla:
BufferUnderflowExceptionparaByteBuffer,EOFExceptionparaDataInputStream, y unaArrayIndexOutOfBoundsExceptiono un resultado incorrecto sin aviso en el código manual. - Orden de bytes: el orden usado al leer debe coincidir con el orden en que se escribieron los bytes;
ByteBufferusa big-endian de forma predeterminada y puede cambiarse conByteOrder, mientras que las lecturas deDataInputStreamsiempre son big-endian y no ofrecen una opción de orden. - Signo y rango:
getInt()yreadInt()devuelven unintcon signo, por lo que un valor de 32 bits sin signo superior aInteger.MAX_VALUEaparecerá como un número inferior a 0. UsaInteger.toUnsignedLong(intValue)o acumula en unlongcuando los datos de origen no tengan signo. - Posición del búfer: reutilizar un
ByteBuffercontinúa desde su posición actual, no desde el principio; llama arewind()o vuelve a usarwrappara releer el array.