Interpretando Big/Little Endian desde Java

21May08

En el post anterior vimos las diferencias entre Big y Little Endian.

En este veremos como interpretar desde Java un array de bytes (que puede provenir de un archivo, una comunicación de red, etc.) como una sucesión de datos, ya sea bytes, enteros, flotantes, etc. Para ello realizaremos las conversiones teniendo en cuenta el endianess con el cual vienen organizados los datos.

Como leer byte por byte un número

Primero que nada veremos como podemos leer cada byte de un dato. Deberemos tener en cuenta las posiciones en bits de cada byte:

Entonces si queremos leer por ejemplo el byte 2 de un entero debemos movernos al bit 16 y tomar el byte que necesitamos desde ese punto
Una forma de realizar esto en Java sería desplazando a la derecha el valor que queremos leer tantos bits como sea necesario de forma que quede ubicado en el byte inicial, luego eliminar todo lo que este fuera del primer byte con una mascara, y finalmente convertirlo a byte.
Gráficamente hacemos esto:

En resumen:

byte d = (byte)((a >> 16) & 0xFF) ;

En el caso inverso, que queramos por ejemplo almacenar un byte en el byte 1 de un entero debemos movernos al bit 8 y a partir de ahí almacenar nuestro byte.
En Java lo que hacemos es convertir el byte al tipo del objetivo (en el ejemplo es un entero), aplicar una mascara de byte para eliminar la basura generada y finalmente desplazarlo a la izquierda los bits necesarios.
Gráficamente hacemos esto:

En resumen:

int d = (a & 0xFF) < < 8;
&#91;/sourcecode&#93;

Si deseamos combinar dos números usamos el operador OR por bits (|) entre ambos, de la forma:

<p style="text-align:center;"><img class="aligncenter size-full wp-image-137" src="https://lefunes.files.wordpress.com/2008/05/03_ejemplo.png" alt="" width="457" height="157" />
<h3>Convirtiendo short</h3>
Un short ocupa 2 bytes en Java por lo que tendremos que tener en cuenta el endianess del dato al momento de convertir desde/hacia un array de bytes.
<h4>Short a byte[]</h4>
Para obtener cada uno de los bytes realizamos:

<p style="text-align:center;"><img class="aligncenter size-full wp-image-138" src="https://lefunes.files.wordpress.com/2008/05/04_obtener_bytes_short.png" alt="" width="472" height="192" /></p>

Para crear un array de bytes en big-endian, debemos almacenarlos en el orden en que los obtuvimos:


byte[] sbe = new byte[]{ b1 ,  b0 };

y para crear un array de bytes en little-endian, debemos almacenarlos en el orden inverso en que los obtuvimos:

byte[] sbe = new byte[]{ b0 ,  b1 };

En resumen, todos los conceptos en un solo método:

public byte[] shortToByteArray(short valor, boolean bigEndian){
     byte[] resultado;
     byte b1 = (byte)(( valor >> 8 ) & 0xFF) ;
     byte b0 = (byte)( valor  & 0xFF) ;
     if(bigEndian){
          resultado = new byte[]{ b1 ,  b0 };
     } else{
          resultado = new byte[]{ b0 ,  b1 };
     }
     return resultado;
}

Byte[] a short

Si queremos obtener un short desde un array de bytes que viene ordenado en big-endian, debemos:

Y en caso de que el array de bytes este ordenado como little-endian:

En resumen, todos los conceptos en un solo método:

public short byteArrayToShort(byte[] valor, boolean bigEndian){
     if(valor. length < 2){
          throw new ArrayIndexOutOfBoundsException(valor. length);
     }
     short a, b ;
     if(bigEndian){
          a = (short)((valor&#91;0&#93; & 0xFF) << 8 );
          b =  (short) (valor&#91;1&#93; & 0xFF);
     } else{
          a = (short)((valor&#91;1&#93; & 0xFF) << 8 );
          b =  (short) (valor&#91;0&#93; & 0xFF) ;
     }
     return  (short)(a | b);
}
&#91;/sourcecode&#93;
<h3>Convirtiendo int
<h4></h4>
Un int ocupa 4 bytes en Java por lo que tendremos que tener en cuenta el endianess del dato al momento de convertir desde/hacia un array de bytes.

<h4>Int a byte[]</h4>
Para obtener cada uno de los bytes realizamos:

<p style="text-align:center;"><img src="https://lefunes.files.wordpress.com/2008/05/07_obtener_bytes_int.png" alt="" width="544" height="225" class="aligncenter size-full wp-image-141" /></p>

Para crear un array de bytes en big-endian, debemos almacenarlos en el orden en que los obtuvimos:


byte[] sbe = new byte[]{ b3 , b2 , b1 ,  b0 };

y para crear un array de bytes en little-endian, debemos almacenarlos en el orden inverso en que los obtuvimos:

byte[] sbe = new byte[]{ b0 ,  b1 , b2 , b3 };

En resumen, todos los conceptos en un solo método:

public byte[] intToByteArray(int valor, boolean bigEndian){
     byte[] resultado; 
     byte b3 = (byte)(( valor >> 24) & 0xFF) ;
     byte b2 = (byte)(( valor >> 16) & 0xFF) ;
     byte b1 = (byte)(( valor >> 8 ) & 0xFF) ;
     byte b0 = (byte)( valor  & 0xFF) ;
     if(bigEndian){
          resultado = new byte[]{ b3 , b2 , b1 , b0 };
     } else{
          resultado = new byte[]{ b0 ,  b1 , b2 , b3 };
     }
     return resultado;
}

Byte[] a int

Siguiendo el mismo concepto que cuando deseamos obtener un short, hacemos:

public int byteArrayToInt(byte[] valor, boolean bigEndian){
     if(valor. length < 4){
          throw new ArrayIndexOutOfBoundsException(valor. length);
     }
     int a, b, c, d;
     if(bigEndian){
          a = (valor&#91;0&#93; & 0xFF) << 24; 
          b = (valor&#91;1&#93; & 0xFF) << 16; 
          c = (valor&#91;2&#93; & 0xFF) << 8; 
          d =  valor&#91;3&#93; & 0xFF;
     } else{
          a = (valor&#91;3&#93; & 0xFF) << 24; 
          b = (valor&#91;2&#93; & 0xFF) << 16; 
          c = (valor&#91;1&#93; & 0xFF) << 8; 
          d =  valor&#91;0&#93; & 0xFF;
     } 
     return  a | b | c | d;
}
&#91;/sourcecode&#93;
<h3>Convirtiendo Long
<h4></h4>
Un long ocupa 8 bytes en Java por lo que como en los casos anteriores, tendremos que tener en cuenta el endianess del dato al momento de convertir desde/hacia un array de bytes.

<h4>Long a byte[]</h4>
Para obtener cada uno de los bytes realizamos:

<p style="text-align:center;"><img src="https://lefunes.files.wordpress.com/2008/05/08_obtener_bytes_long.png" alt="" width="544" height="236" class="aligncenter size-full wp-image-142" /></p>

Para crear un array de bytes en big-endian, debemos almacenarlos en el orden en que los obtuvimos:


byte[] sbe = new byte[]{ b7 , b6 , b5 , b4 , b3 , b2 , b1 ,  b0 };

y para crear un array de bytes en little-endian, debemos almacenarlos en el orden inverso en que los obtuvimos:

byte[] sbe = new byte[]{ b0 ,  b1 , b2 , b3 , b4 , b5 , b6 , b7 };

En resumen, todos los conceptos en un solo método:

public byte[] longToByteArray(long valor, boolean bigEndian){
     byte[] resultado; 
     byte b7 = (byte)(( valor >> 56) & 0xFF) ;
     byte b6 = (byte)(( valor >> 48 ) & 0xFF) ;
     byte b5 = (byte)(( valor >> 40) & 0xFF) ; 
     byte b4 = (byte)(( valor >> 32) & 0xFF) ;
     byte b3 = (byte)(( valor >> 24) & 0xFF) ;
     byte b2 = (byte)(( valor >> 16) & 0xFF) ;
     byte b1 = (byte)(( valor >> 8 ) & 0xFF) ;
     byte b0 = (byte)( valor  & 0xFF) ;
     if(bigEndian){
          resultado = new byte[]{ b7 , b6 , b5 , b4 , b3 , b2 , b1 , b0 };
     } else{
          resultado = new byte[]{ b0 ,  b1 , b2 , b3 , b4 , b5 , b6 , b7 };
     }
     return resultado;
}

Byte[] a long

Siguiendo los mismos conceptos anteriores, hacemos:

public long byteArrayToLong(byte[] valor, boolean bigEndian){
     if(valor. length < 8 ){
          throw new ArrayIndexOutOfBoundsException(valor. length);
     }
     long a, b, c, d, e, f, g, h;
     if(bigEndian){
          a = (long)(valor&#91;0&#93; & 0xFF) << 56;
          b = (long)(valor&#91;1&#93; & 0xFF) << 48;
          c = (long)(valor&#91;2&#93; & 0xFF) << 40;
          d = (long)(valor&#91;3&#93; & 0xFF) << 32;
          e = (long)(valor&#91;4&#93; & 0xFF) << 24;
          f = (long)(valor&#91;5&#93; & 0xFF) << 16;
          g = (long)(valor&#91;6&#93; & 0xFF) << 8;
          h = (long)(valor&#91;7&#93; & 0xFF);
     } else {
          a = (long)(valor&#91;7&#93; & 0xFF) << 56;
          b = (long)(valor&#91;6&#93; & 0xFF) << 48;
          c = (long)(valor&#91;5&#93; & 0xFF) << 40;
          d = (long)(valor&#91;4&#93; & 0xFF) << 32;
          e = (long)(valor&#91;3&#93; & 0xFF) << 24;
          f = (long)(valor&#91;2&#93; & 0xFF) << 16;
          g = (long)(valor&#91;1&#93; & 0xFF) << 8;
          h = (long)(valor&#91;0&#93; & 0xFF);
     } 
     return  a | b | c | d | e | f | g | h;
} 
&#91;/sourcecode&#93;

<h3>Convirtiendo Float
<h4></h4>
Un long ocupa 4 bytes en Java, al igual que el int, por lo que los mecanismos de conversión desde/hacia un array de bytes son también los mismos, cambiando solamente que antes debemos generar/obtener el entero equivalente a nuestro float (a nivel de bits).
Para facilitarnos las cosas la clase Float posee métodos que realizan este trabajo por nosotros.

<h4>Long a byte[] </h4>
Lo que hacemos primero es obtener el int equivalente y luego realizamos el mismo procedimiento que antes:


public byte[] floatToByteArray(float valor, boolean bigEndian){ 
     int enteroEquivalente = Float .floatToIntBits(valor);
     return intToByteArray(enteroEquivalente, bigEndian);
}

Byte[] a float

Nuevamente lo que hacemos es conseguir el int equivalente desde los bytes, y de ahí convertimos al float buscado:

public float byteArrayToFloat(byte[] valor, boolean bigEndian){
      int enteroEquivalente = byteArrayToInt (valor, bigEndian);
     return Float.intBitsToFloat(enteroEquivalente);
} 

Convirtiendo Double

Un double ocupa 8 bytes en Java, al igual que el long, repitiendo el paso anterior, asi como lo que los mecanismos de conversión desde/hacia un array de bytes son también los mismos, cambiando solamente que antes debemos generar/obtener el long equivalente a nuestro double (a nivel de bits).
Para facilitarnos las cosas la clase Double posee métodos que realizan este trabajo por nosotros.

Double a byte[]

Lo que hacemos primero es obtener el long equivalente y luego realizamos el mismo procedimiento que antes:

public byte[] doubleToByteArray(double valor, boolean bigEndian){ 
     long longEquivalente = Double.doubleToLongBits(valor);
     return longToByteArray(longEquivalente, bigEndian);
}

Byte[] a double

Nuevamente lo que hacemos es conseguir un long equivalente desde los bytes, y de ahí convertimos al double buscado:

public double byteArrayToDouble(byte[] valor, boolean bigEndian){
      long longEquivalente = byteArrayToLong (valor, bigEndian);
     return Double.longBitsToDouble(longEquivalente);
 }

Una clase de ejemplo

Para realizar una mejora podríamos definir una enumeración que indique el orden de los bytes:

public enum OrdenEndian {
    BIG_ENDIAN,
    LITTLE_ENDIAN
}

y generar una clase que contenga todos los métodos vistos anteriormente:

public class Endianness {
    private static final int MASCARA_BYTE = 0xFF;

    /**
     * Convierte short a un byte array respetando el orden asignado
     * 
     * @param valor valor a convertir
     * @param endianness orden a utilizar en la conversion
     * @return array de bytes equivalentes a valor
     */
    public static byte[] shortToByteArray(short valor, OrdenEndian endianness) {
        byte[] resultado;
        byte b1 = (byte) ((valor >> 8 ) & MASCARA_BYTE);
        byte b0 = (byte) (valor & MASCARA_BYTE);
        if (endianness == OrdenEndian.BIG_ENDIAN) {
            resultado = new byte[]{b1, b0};
        } else {
            resultado = new byte[]{b0, b1};
        }
        return resultado;
    }

    /**
     * Convierte un array de bytes a un short respetando el orden asignado
     * 
     * @param valor array de bytes a convertir
     * @param endianness orden a utilizar en la conversion
     * @return valor equivalente despues de la conversion
     */
    public static short byteArrayToShort(byte[] valor, OrdenEndian endianness) {
        if (valor.length < 2) {
            throw new ArrayIndexOutOfBoundsException(valor.length);
        }
        short a, b;
        if (endianness == OrdenEndian.BIG_ENDIAN) {
            a = (short) ((valor&#91;0&#93; & MASCARA_BYTE) << 8 );
            b = (short) (valor&#91;1&#93; & MASCARA_BYTE);
        } else {
            a = (short) ((valor&#91;1&#93; & MASCARA_BYTE) << 8 );
            b = (short) (valor&#91;0&#93; & MASCARA_BYTE);
        }
        return (short) (a | b);
    }

    /**
     * Convierte int a un byte array respetando el orden asignado
     * 
     * @param valor valor a convertir
     * @param endianness orden a utilizar en la conversion
     * @return array de bytes equivalentes a valor
     */
    public static byte&#91;&#93; intToByteArray(int valor, OrdenEndian endianness) {
        byte&#91;&#93; resultado;
        byte b3 = (byte) ((valor >> 24) & MASCARA_BYTE);
        byte b2 = (byte) ((valor >> 16) & MASCARA_BYTE);
        byte b1 = (byte) ((valor >> 8 ) & MASCARA_BYTE);
        byte b0 = (byte) (valor & MASCARA_BYTE);
        if (endianness == OrdenEndian.BIG_ENDIAN) {
            resultado = new byte[]{b3, b2, b1, b0};
        } else {
            resultado = new byte[]{b0, b1, b2, b3};
        }
        return resultado;
    }

    /**
     * Convierte un array de bytes a un int respetando el orden asignado
     * 
     * @param valor array de bytes a convertir
     * @param endianness orden a utilizar en la conversion
     * @return valor equivalente despues de la conversion
     */
    public static int byteArrayToInt(byte[] valor, OrdenEndian endianness) {
        if (valor.length < 4) {
            throw new ArrayIndexOutOfBoundsException(valor.length);
        }
        int a, b, c, d;
        if (endianness == OrdenEndian.BIG_ENDIAN) {
            a = (valor&#91;0&#93; & MASCARA_BYTE) << 24;
            b = (valor&#91;1&#93; & MASCARA_BYTE) << 16;
            c = (valor&#91;2&#93; & MASCARA_BYTE) << 8;
            d = valor&#91;3&#93; & MASCARA_BYTE;
        } else {
            a = (valor&#91;3&#93; & MASCARA_BYTE) << 24;
            b = (valor&#91;2&#93; & MASCARA_BYTE) << 16;
            c = (valor&#91;1&#93; & MASCARA_BYTE) << 8;
            d = valor&#91;0&#93; & MASCARA_BYTE;
        }
        return a | b | c | d;
    }

    /**
     * Convierte long a un byte array respetando el orden asignado
     * 
     * @param valor valor a convertir
     * @param endianness orden a utilizar en la conversion
     * @return array de bytes equivalentes a valor
     */
    public static byte&#91;&#93; longToByteArray(long valor, OrdenEndian endianness) {
        byte&#91;&#93; resultado;
        byte b7 = (byte) ((valor >> 56) & MASCARA_BYTE);
        byte b6 = (byte) ((valor >> 48 ) & MASCARA_BYTE);
        byte b5 = (byte) ((valor >> 40) & MASCARA_BYTE);
        byte b4 = (byte) ((valor >> 32) & MASCARA_BYTE);
        byte b3 = (byte) ((valor >> 24) & MASCARA_BYTE);
        byte b2 = (byte) ((valor >> 16) & MASCARA_BYTE);
        byte b1 = (byte) ((valor >> 8 ) & MASCARA_BYTE);
        byte b0 = (byte) (valor & MASCARA_BYTE);
        if (endianness == OrdenEndian.BIG_ENDIAN) {
            resultado = new byte[]{b7, b6, b5, b4, b3, b2, b1, b0};
        } else {
            resultado = new byte[]{b0, b1, b2, b3, b4, b5, b6, b7};
        }
        return resultado;
    }

    /**
     * Convierte un array de bytes a un long respetando el orden asignado
     * 
     * @param valor array de bytes a convertir
     * @param endianness orden a utilizar en la conversion
     * @return valor equivalente despues de la conversion
     */
    public static long byteArrayToLong(byte[] valor, OrdenEndian endianness) {
        if (valor.length < 8 ){
            throw new ArrayIndexOutOfBoundsException(valor.length);
        }
        long a, b, c, d, e, f, g, h;
        if (endianness == OrdenEndian.BIG_ENDIAN) {
            a = (long) (valor&#91;0&#93; & MASCARA_BYTE) << 56;
            b = (long) (valor&#91;1&#93; & MASCARA_BYTE) << 48;
            c = (long) (valor&#91;2&#93; & MASCARA_BYTE) << 40;
            d = (long) (valor&#91;3&#93; & MASCARA_BYTE) << 32;
            e = (long) (valor&#91;4&#93; & MASCARA_BYTE) << 24;
            f = (long) (valor&#91;5&#93; & MASCARA_BYTE) << 16;
            g = (long) (valor&#91;6&#93; & MASCARA_BYTE) << 8;
            h = (long) (valor&#91;7&#93; & MASCARA_BYTE);
        } else {
            a = (long) (valor&#91;7&#93; & MASCARA_BYTE) << 56;
            b = (long) (valor&#91;6&#93; & MASCARA_BYTE) << 48;
            c = (long) (valor&#91;5&#93; & MASCARA_BYTE) << 40;
            d = (long) (valor&#91;4&#93; & MASCARA_BYTE) << 32;
            e = (long) (valor&#91;3&#93; & MASCARA_BYTE) << 24;
            f = (long) (valor&#91;2&#93; & MASCARA_BYTE) << 16;
            g = (long) (valor&#91;1&#93; & MASCARA_BYTE) << 8;
            h = (long) (valor&#91;0&#93; & MASCARA_BYTE);
        }
        return a | b | c | d | e | f | g | h;
    }

    /**
     * Convierte float a un byte array respetando el orden asignado
     * 
     * @param valor valor a convertir
     * @param endianness orden a utilizar en la conversion
     * @return array de bytes equivalentes a valor
     */
    public static byte&#91;&#93; floatToByteArray(float valor, OrdenEndian endianness) {
        int enteroEquivalente = Float.floatToIntBits(valor);
        return intToByteArray(enteroEquivalente, endianness);
    }

    /**
     * Convierte un array de bytes a un float respetando el orden asignado
     * 
     * @param valor array de bytes a convertir
     * @param endianness orden a utilizar en la conversion
     * @return valor equivalente despues de la conversion
     */
    public static float byteArrayToFloat(byte&#91;&#93; valor, OrdenEndian endianness) {
        int enteroEquivalente = byteArrayToInt(valor, endianness);
        return Float.intBitsToFloat(enteroEquivalente);
    }

    /**
     * Convierte double a un byte array respetando el orden asignado
     * 
     * @param valor valor a convertir
     * @param endianness orden a utilizar en la conversion
     * @return array de bytes equivalentes a valor
     */
    public static byte&#91;&#93; doubleToByteArray(double valor, OrdenEndian endianness) {
        long longEquivalente = Double.doubleToLongBits(valor);
        return longToByteArray(longEquivalente, endianness);
    }

    /**
     * Convierte un array de bytes a un double respetando el orden asignado
     * 
     * @param valor array de bytes a convertir
     * @param endianness orden a utilizar en la conversion
     * @return valor equivalente despues de la conversion
     */
    public double byteArrayToDouble(byte&#91;&#93; valor, OrdenEndian endianness) {
        long longEquivalente = byteArrayToLong(valor, endianness);
        return Double.longBitsToDouble(longEquivalente);
    }
}
&#91;/sourcecode&#93;

<h3>Utilizando la clase de ejemplo
<h4></h4>
Por ejemplo si necesitamos leer/escribir desde una fuente de datos una clase, por ejemplo:


public class ClaseEjemplo {
    private int a;
    private short b;
    private short c;

    public ClaseEjemplo() {
    }
    public ClaseEjemplo(int A, short B, short C) {
        this.a = A;
        this.b = B;
        this.c = C;
    }

    public int getA() {
        return a;
    }
    public void setA(int a) {
        this.a = a;
    }

    public short getB() {
        return b;
    }
    public void setB(short b) {
        this.b = b;
    }

    public short getC() {
        return c;
    }
    public void setC(short c) {
        this.c = c;
    }

    @Override
    public String toString() {
        return "ClaseEjemplo: " + a + " ; " + b + " ; " + c;
    }
}

y supongamos que poseemos la siguiente condición de formato del array de datos:

Podríamos escribir un parser valiéndonos de la clase de utilitaria que definimos recién:

public class ParserClaseEjemplo {

    public static ClaseEjemplo toClaseEjemplo(byte[] valor) {
        ClaseEjemplo ce = new ClaseEjemplo();

        byte[] ba = Arrays.copyOfRange(valor, 0, 4);
        int a = Endianness.byteArrayToInt(ba, OrdenEndian.BIG_ENDIAN);
        ce.setA(a);

        byte[] bb = Arrays.copyOfRange(valor, 4, 6);
        short b = Endianness.byteArrayToShort(bb, OrdenEndian.LITTLE_ENDIAN);
        ce.setB(b);

        byte[] bc = Arrays.copyOfRange(valor, 6, 8 );
        short c = Endianness.byteArrayToShort(bc, OrdenEndian.BIG_ENDIAN);
        ce.setC(c);

        return ce;
    }

    public static byte[] toByteArray(ClaseEjemplo valor) {
        byte[] ba = new byte[8];

        byte[] a = Endianness.intToByteArray(valor.getA(), OrdenEndian.BIG_ENDIAN);
        byte[] b = Endianness.shortToByteArray(valor.getB(), OrdenEndian.LITTLE_ENDIAN);
        byte[] c = Endianness.shortToByteArray(valor.getC(), OrdenEndian.BIG_ENDIAN);

        int ini = 0;
        ini = copiarBytes(ba, a, ini);
        ini = copiarBytes(ba, b, ini);
        ini = copiarBytes(ba, c, ini);
        
        return ba;
    }
    
    private static int copiarBytes(final byte[] destino, final byte[] origen, final int inicio) {
        for (int i = 0; i &lt; origen.length; i++) {
            destino[i + inicio] = origen[i];
        }
        return origen.length + inicio;
    }
}

Podemos probar que funciona ejecutando:

public class Prueba {
    public static void main(String[] args) {
        byte a = (byte) 0x00;
        byte b = (byte) 0x00;
        byte c = (byte) 0x00;
        byte d = (byte) 0x01;
        byte e = (byte) 0x02;
        byte f = (byte) 0x00;
        byte g = (byte) 0x00;
        byte h = (byte) 0x03;
        byte[] bb = new byte[]{a, b, c, d, e, f, g, h};

        ClaseEjemplo ce = ParserClaseEjemplo.toClaseEjemplo(bb);
        System.out.println(ce.toString());
        
        byte[] cc = ParserClaseEjemplo.toByteArray(ce);
        System.out.println(Arrays.toString(cc));
    }
}

En un próximo post veremos como realizar lo mismo utilizando esta vez la clase ByteBuffer.
Hasta la próxima.

Más Info

Endianess: Big-Endian y Little-Endian



6 Responses to “Interpretando Big/Little Endian desde Java”

  1. 1 Ismael

    Excelente manual, muchas gracias..

  2. 2 Pregunta

    Excelente manual, es muy claro, es didáctico y a prueba de errores…

    Sin embargo, tengo una duda.

    Si se capturan bytes en donde previamente se ha almacenado datos de tipo Short o de tipo Integer.

    ¿Existe alguna diferencia en el tratamiento si son Signed or Unsigned?

    Gracias…

  3. 3 AtoM

    Excelente entrada, aunque me quedo con las ganas de verlo con ByteBuffer.

  4. 4 angel

    muy útil!, gracias

  5. 5 Jorge

    Impresionante estimado, ya estás en Mis Favoritos.

    Jorge (Uruguay)


  1. 1 Endianess: Big-Endian y Little-Endian « Le Funes

A %d blogueros les gusta esto: