Байт-массив и преобразование Int в Java

У меня возникают некоторые трудности с этими двумя функциями: byteArrayToInt и intToByteArray.

Проблема заключается в том, что если я использую один, чтобы перейти к другому, и это результат для первого, результаты будут разными, как вы можете видеть из моих примеров ниже.

Я не могу найти ошибку в коде. Любые идеи очень приветствуются. Спасибо.

public static void main(String[] args)
{
    int a = 123;
    byte[] aBytes = intToByteArray(a);
    int a2 = byteArrayToInt(aBytes);

    System.out.println(a);         // prints '123'
    System.out.println(aBytes);    // prints '[[email protected]'
    System.out.println(a2);        // prints '2063597568
            System.out.println(intToByteArray(a2));  // prints '[[email protected]'
}

public static int byteArrayToInt(byte[] b) 
{
    int value = 0;
    for (int i = 0; i < 4; i++) {
        int shift = (4 - 1 - i) * 8;
        value += (b[i] & 0x000000FF) << shift;
    }
    return value;
}

public static byte[] intToByteArray(int a)
{
    byte[] ret = new byte[4];
    ret[0] = (byte) (a & 0xFF);   
    ret[1] = (byte) ((a >> 8) & 0xFF);   
    ret[2] = (byte) ((a >> 16) & 0xFF);   
    ret[3] = (byte) ((a >> 24) & 0xFF);
    return ret;
}

Ответ 1

Вы переключаете endianness между двумя вашими методами. У вас есть intToByteArray(int a) назначение младших бит в ret[0], но затем byteArrayToInt(byte[] b) присваивает b[0] старшим битам результата. Вы должны инвертировать тот или иной, например:

public static byte[] intToByteArray(int a)
{
    byte[] ret = new byte[4];
    ret[3] = (byte) (a & 0xFF);   
    ret[2] = (byte) ((a >> 8) & 0xFF);   
    ret[1] = (byte) ((a >> 16) & 0xFF);   
    ret[0] = (byte) ((a >> 24) & 0xFF);
    return ret;
}

Ответ 2

Ваши методы должны быть (что-то типа)

public static int byteArrayToInt(byte[] b) 
{
    return   b[3] & 0xFF |
            (b[2] & 0xFF) << 8 |
            (b[1] & 0xFF) << 16 |
            (b[0] & 0xFF) << 24;
}

public static byte[] intToByteArray(int a)
{
    return new byte[] {
        (byte) ((a >> 24) & 0xFF),
        (byte) ((a >> 16) & 0xFF),   
        (byte) ((a >> 8) & 0xFF),   
        (byte) (a & 0xFF)
    };
}

Эти методы были протестированы с помощью следующего кода:

Random rand = new Random(System.currentTimeMillis());
byte[] b;
int a, v;
for (int i=0; i<10000000; i++) {
    a = rand.nextInt();
    b = intToByteArray(a);
    v = byteArrayToInt(b);
    if (a != v) {
        System.out.println("ERR! " + a + " != " + Arrays.toString(b) + " != " + v);
    }
}
System.out.println("Done!");

Ответ 3

Это большая работа для:

public static int byteArrayToLeInt(byte[] b) {
    final ByteBuffer bb = ByteBuffer.wrap(b);
    bb.order(ByteOrder.LITTLE_ENDIAN);
    return bb.getInt();
}

public static byte[] leIntToByteArray(int i) {
    final ByteBuffer bb = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE);
    bb.order(ByteOrder.LITTLE_ENDIAN);
    bb.putInt(i);
    return bb.array();
}

Этот метод использует Java ByteBuffer и ByteOrder в пакете java.nio. Этот код должен быть предпочтительным, когда требуется чтение. Это также должно быть очень легко запомнить.

Здесь показан порядок байтов Little Endian. Чтобы создать версию Big Endian, вы можете просто отказаться от вызова order(ByteOrder).


В коде, где производительность выше приоритета, чем читаемость (примерно в 10 раз):

public static int byteArrayToLeInt(byte[] encodedValue) {
    int value = (encodedValue[3] << (Byte.SIZE * 3));
    value |= (encodedValue[2] & 0xFF) << (Byte.SIZE * 2);
    value |= (encodedValue[1] & 0xFF) << (Byte.SIZE * 1);
    value |= (encodedValue[0] & 0xFF);
    return value;
}

public static byte[] leIntToByteArray(int value) {
    byte[] encodedValue = new byte[Integer.SIZE / Byte.SIZE];
    encodedValue[3] = (byte) (value >> Byte.SIZE * 3);
    encodedValue[2] = (byte) (value >> Byte.SIZE * 2);   
    encodedValue[1] = (byte) (value >> Byte.SIZE);   
    encodedValue[0] = (byte) value;
    return encodedValue;
}

Просто отмените индекс байтового массива на число от нуля до трех, чтобы создать версию этого кода с большим эндиантом.


Примечания:

  • В Java 8 вы также можете использовать константу Integer.BYTES, которая более кратка, чем Integer.SIZE / Byte.SIZE.

Ответ 4

Вы также можете использовать BigInteger для байтов переменной длины. Вы можете преобразовать его в Long, Integer или Short, в зависимости от ваших потребностей.

new BigInteger(bytes).intValue();

или обозначить полярность:

new BigInteger(1, bytes).intValue();

Чтобы просто вернуть байты:

new BigInteger(bytes).toByteArray()

Ответ 5

Мне нравится исходный ответ owlstead, и если вам не нравится идея создания ByteBuffer для каждого вызова метода, вы можете повторно использовать ByteBuffer, называя его методами .clear() и .flip():

ByteBuffer _intShifter = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE)
                                   .order(ByteOrder.LITTLE_ENDIAN);

public byte[] intToByte(int value) {
    _intShifter.clear();
    _intShifter.putInt(value);      
    return _intShifter.array();
}

public int byteToInt(byte[] data)
{
    _intShifter.clear();
    _intShifter.put(data, 0, Integer.SIZE / Byte.SIZE);
    _intShifter.flip();
    return _intShifter.getInt();
}

Ответ 6

Я нашел простой способ в com.google.common.primitives, который находится в [Maven: com.google.guava: guava: 12.0.1]

long newLong = Longs.fromByteArray(oldLongByteArray);
int newInt = Ints.fromByteArray(oldIntByteArray);

Попробуйте:)

Ответ 7

Я долго смотрел на многие вопросы, подобные этому, и нашел этот пост... Мне не понравилось, что преобразование код дублируется для каждого типа, поэтому я сделал общий метод для выполнения задачи:

public static byte[] toByteArray(long value, int n)
{
    byte[] ret = new byte[n];
    ret[n-1] = (byte) ((value >> (0*8) & 0xFF);   
    ret[n-2] = (byte) ((value >> (1*8) & 0xFF);   
    ...
    ret[1] = (byte) ((value >> ((n-2)*8) & 0xFF);   
    ret[0] = (byte) ((value >> ((n-1)*8) & 0xFF);   
    return ret;
}

См. полный пост.

Ответ 8

/* Извините, это правильный */

     public byte[] IntArrayToByteArray(int[] iarray , int sizeofintarray)
     {
       final ByteBuffer bb ;
       bb = ByteBuffer.allocate( sizeofintarray * 4);
       for(int k = 0; k < sizeofintarray ; k++)
       bb.putInt(k * 4, iar[k]);
       return bb.array();
     }

Ответ 9

Вместо выделения пространства и т.д. подход с использованием ByteBuffer от java.nio....

byte[] arr = { 0x01, 0x00, 0x00, 0x00, 0x48, 0x01};

// say we want to consider indices 1, 2, 3, 4 {0x00, 0x00, 0x00, 0x48};
ByteBuffer bf = ByteBuffer.wrap(arr, 1, 4); // big endian by default
int num = bf.getInt();    // 72

Теперь, чтобы пойти другим путем.

ByteBuffer newBuf = ByteBuffer.allocate(4);
newBuf.putInt(num);
byte[] bytes = newBuf.array();  // [0, 0, 0, 72] {0x48 = 72}

Ответ 10

вот моя реализация

public static byte[] intToByteArray(int a) {
    return BigInteger.valueOf(a).toByteArray();
}

public static int byteArrayToInt(byte[] b) {
    return new BigInteger(b).intValue();
}