简体   繁体   English

Java中的字节数组和Int转换

[英]Byte Array and Int conversion in Java

I am having some difficulty with these two functions: byteArrayToInt and intToByteArray . 我对这两个函数有一些困难: byteArrayToIntintToByteArray

The problem is that if I use one to get to another and that result to get to the former, the results are different, as you can see from my examples below. 问题是,如果我使用一个来到另一个并且结果到达前者,结果会有所不同,您可以从下面的示例中看到。

I cannot find the bug in the code. 我找不到代码中的错误。 Any ideas are very welcome. 任何想法都非常受欢迎。 Thanks. 谢谢。

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 '[B@459189e1'
    System.out.println(a2);        // prints '2063597568
            System.out.println(intToByteArray(a2));  // prints '[B@459189e1'
}

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;
}

Your methods should be (something like) 你的方法应该是(类似的)

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)
    };
}

These methods were tested with the following code : 使用以下代码测试了这些方法:

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!");

That's a lot of work for: 这是很多工作:

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();
}

This method uses the Java ByteBuffer and ByteOrder functionality in the java.nio package. 此方法使用java.nio包中的Java ByteBufferByteOrder功能。 This code should be preferred where readability is required. 在需要可读性的情况下,此代码应该是首选。 It should also be very easy to remember. 它也应该很容易记住。

I've shown Little Endian byte order here. 我在这里显示了Little Endian字节顺序。 To create a Big Endian version you can simply leave out the call to order(ByteOrder) . 要创建Big Endian版本,您可以简单地省略对order(ByteOrder)的调用order(ByteOrder)


In code where performance is higher priority than readability (about 10x as fast): 在性能优先于可读性的代码中(大约快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;
}

Just reverse the byte array index to count from zero to three to create a Big Endian version of this code. 只需将字节数组索引反转为从0到3的计数,即可创建此代码的Big Endian版本。


Notes: 笔记:

  • In Java 8 you can also make use of the Integer.BYTES constant, which is more succinct than Integer.SIZE / Byte.SIZE . 在Java 8中,您还可以使用Integer.BYTES常量,该常量比Integer.SIZE / Byte.SIZE更简洁。

You're swapping endianness between your two methods. 您正在交换两种方法之间的字节顺序 You have intToByteArray(int a) assigning the low-order bits into ret[0] , but then byteArrayToInt(byte[] b) assigns b[0] to the high-order bits of the result. 你有intToByteArray(int a)将低位分配给ret[0] ,但是byteArrayToInt(byte[] b)b[0]赋给结果的高位。 You need to invert one or the other, like: 您需要反转其中一个,例如:

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;
}

You can also use BigInteger for variable length bytes. 您还可以将BigInteger用于可变长度字节。 You can convert it to Long, Integer or Short, whichever suits your needs. 您可以将其转换为Long,Integer或Short,以满足您的需求。

new BigInteger(bytes).intValue();

or to denote polarity: 或表示极性:

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

To get bytes back just: 要获取字节只是:

new BigInteger(bytes).toByteArray()

I like owlstead's original answer, and if you don't like the idea of creating a ByteBuffer on every method call then you can reuse the ByteBuffer by calling it's .clear() and .flip() methods: 我喜欢owlstead的原始答案,如果你不喜欢在每个方法调用上创建一个ByteBuffer的想法,那么你可以通过调用它的.clear().flip()方法来重用ByteBuffer

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();
}

I found a simple way in com.google.common.primitives which is in the [Maven:com.google.guava:guava:12.0.1] 我在com.google.common.primitives中找到了一个简单的方法,它位于[Maven:com.google.guava:guava:12.0.1]中

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

Have a nice try :) 试试看:)

I took a long look at many questions like this, and found this post ... I didn't like the fact that the conversion code is duplicated for each type, so I've made a generic method to perform the task: 我仔细看了很多像这样的问题,发现这个帖子 ......我不喜欢每种类型的转换代码都是重复的,所以我做了一个通用的方法来执行任务:

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;
}

See full post . 查看完整帖子

/*sorry this is the correct */ / *抱歉这是正确的* /

     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();
     }

Instead of allocating space, et al, an approach using ByteBuffer from java.nio .... 而不是分配空间,等等,使用来自java.nio ByteBuffer的方法....

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

Now, to go the other way. 现在,走另一条路。

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

here is my implementation 这是我的实施

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM