如何在Java中有效地改变字节数组的字节顺序

时间:2014-01-13 09:27:02

标签: java arrays bytearray endianness

我有一长串字节,表示大图片的abgr32像素数据(0xAABBGGRR)。 有没有一种有效的方法来改变java中这个长字节数组的持久性?

例如:

源字节数组是[FF,11,22,33,FF,12,34,11,..........]

是否可以将其转换为此类[33,22,11,FF,11,34,12,FF,....]? 效率很重要。

我尝试使用ByteBuffer.order(ByteOrder.LITTLE_ENDIAN)和ByteBuffer.order(ByteOrder.BIG_ENDIAN)转换,但它没有帮助。

感谢您的帮助。

4 个答案:

答案 0 :(得分:4)

首先:您确定需要更改它吗?本机Java BufferedImage.TYPE_4BYTE_ABGR应该适用于此像素布局......

现在,如果你真的需要更改字节顺序,将数组包装在字节缓冲区中,使用ByteBuffer.order(ByteOrder.LITTLE_ENDIAN)应该可行。只记得你必须从字节缓冲区读取/获取整数,因为在这种情况下字节顺序具有重要性。更改字节顺序不会更改字节的内部顺序,只是多字节类型(short, int, long解释的方式。

这两个版本都不进行数组重新排序,因此可能比重新排序的任何版本更快。如果您真的想重新排序,请参阅主题中的其他答案。

答案 1 :(得分:3)

您可以尝试通过交换相邻4个字节的每组中的字节来手动执行此操作。 此代码假定数组的长度是4的倍数。

for (int i = 0; i < arr.length; i += 4) {
  int tmp;
  // swap 0 and 3
  tmp = arr[i];
  arr[i] = arr[i + 3];
  arr[i + 3] = tmp;
  // swap 1 and 2
  tmp = arr[i + 1];
  arr[i + 1] = arr[i + 2];
  arr[i + 2] = tmp;
}

虽然这在技术上是解决问题的方法,但找到一个不具有字符串敏感性的解决方案可能更明智(如上面的一些评论)。

答案 2 :(得分:2)

使用Unsafe可以做一些技巧更快,但最简单的方法是确保代码预热。

public static void swapIntBytes(byte[] bytes) {
    assert bytes.length % 4 == 0;
    for (int i = 0; i < bytes.length; i += 4) {
        // swap 0 and 3
        byte tmp = bytes[i];
        bytes[i] = bytes[i + 3];
        bytes[i + 3] = tmp;
        // swap 1 and 2
        byte tmp2 = bytes[i + 1];
        bytes[i + 1] = bytes[i + 2];
        bytes[i + 2] = tmp2;
    }
}

public static void swapIntBytes2(byte[] bytes) {
    assert bytes.length % 4 == 0;
    IntBuffer bb1 = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).asIntBuffer();
    IntBuffer bb2 = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();
    bb1.put(bb2);
}

public static void swapIntBytes3(byte[] bytes) {
    assert bytes.length % 4 == 0;
    for (int i = 0; i < bytes.length; i += 4)
        UNSAFE.putInt(bytes, BYTES_OFFSET + i, Integer.reverseBytes(UNSAFE.getInt(bytes, BYTES_OFFSET + i)));
}

public static void main(String... ignored) {
    byte[] bytes = {1, 2, 3, 4, 5, 6, 7, 8};
    swapIntBytes3(bytes);
    System.out.println(Arrays.toString(bytes));

    byte[] bytes4k = new byte[16384];
    for (int i = 0; i < 20; i++) {
        long start = System.nanoTime();
        swapIntBytes(bytes4k);
        long mid1 = System.nanoTime();
        swapIntBytes2(bytes4k);
        long mid2 = System.nanoTime();
        swapIntBytes3(bytes4k);
        long end = System.nanoTime();
        System.out.printf("Swap byte[] %.1f us, Swap IntBuffer %.1f us, Swap UNSAFE %.1f%n",
                (mid1 - start) / 1e3, (mid2 - mid1) / 1e3, (end - mid2) / 1e3);
    }
}

static final Unsafe UNSAFE;
static final int BYTES_OFFSET;

static {
    try {
        @SuppressWarnings("ALL")
        Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafe.setAccessible(true);
        UNSAFE = (Unsafe) theUnsafe.get(null);
        BYTES_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);

    } catch (Exception e) {
        throw new AssertionError(e);
    }
}

打印

[4, 3, 2, 1, 8, 7, 6, 5]
Swap byte[] 433.8 us, Swap IntBuffer 8577.8 us, Swap UNSAFE 1711.8
Swap byte[] 244.6 us, Swap IntBuffer 5773.1 us, Swap UNSAFE 1764.0
Swap byte[] 247.5 us, Swap IntBuffer 5059.7 us, Swap UNSAFE 1756.3
Swap byte[] 255.7 us, Swap IntBuffer 416.9 us, Swap UNSAFE 563.6
Swap byte[] 441.7 us, Swap IntBuffer 437.6 us, Swap UNSAFE 597.4
Swap byte[] 12.1 us, Swap IntBuffer 466.9 us, Swap UNSAFE 632.7
Swap byte[] 11.6 us, Swap IntBuffer 448.4 us, Swap UNSAFE 7.8
Swap byte[] 10.7 us, Swap IntBuffer 415.4 us, Swap UNSAFE 7.0
Swap byte[] 10.2 us, Swap IntBuffer 426.1 us, Swap UNSAFE 6.6
Swap byte[] 9.1 us, Swap IntBuffer 49.0 us, Swap UNSAFE 3.4
Swap byte[] 5.9 us, Swap IntBuffer 24.4 us, Swap UNSAFE 3.1
Swap byte[] 6.0 us, Swap IntBuffer 24.3 us, Swap UNSAFE 3.2
Swap byte[] 5.9 us, Swap IntBuffer 24.2 us, Swap UNSAFE 3.1
Swap byte[] 5.9 us, Swap IntBuffer 24.2 us, Swap UNSAFE 3.1
Swap byte[] 5.9 us, Swap IntBuffer 24.1 us, Swap UNSAFE 3.1
Swap byte[] 5.9 us, Swap IntBuffer 24.2 us, Swap UNSAFE 3.1
Swap byte[] 5.9 us, Swap IntBuffer 24.2 us, Swap UNSAFE 3.1
Swap byte[] 6.6 us, Swap IntBuffer 27.1 us, Swap UNSAFE 3.5
Swap byte[] 5.9 us, Swap IntBuffer 24.2 us, Swap UNSAFE 3.1
Swap byte[] 6.7 us, Swap IntBuffer 27.1 us, Swap UNSAFE 3.5

答案 3 :(得分:0)

我只想进行一次简单的迭代:

for (int i=0; i<array.length; i+=4)
{
    int sum03 = array[i+0]+array[i+3];
    int sum12 = array[i+1]+array[i+2];
    array[i+0] = sum03 - array[i+0];
    array[i+1] = sum12 - array[i+1];
    array[i+2] = sum12 - array[i+2];
    array[i+3] = sum03 - array[i+3];
}

如果您知道如何告诉编译器应用某种循环展开优化,它可能比“传统交换”更快。