如何有效地更改Java中字节数组的字节序

问题描述 投票:3回答:5

我有一个长字节数组,代表一个大图片的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)转换,但没有帮助。

谢谢您的帮助。

java arrays bytearray endianness
5个回答
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;
}

尽管从技术上讲这是解决问题的方法,但找到对字节序不敏感的解决方案(如上述某些评论)可能更明智。


6
投票

首先:确定要更改它吗?原生Java BufferedImage.TYPE_4BYTE_ABGR应该可以在这种像素布局下正常工作...

现在,如果您确实需要更改字节顺序,则使用ByteBuffer.order(ByteOrder.LITTLE_ENDIAN)将数组包装在字节缓冲区中。只需记住字节缓冲区中的您必须读取/获取整数,在这种情况下字节顺序才有意义。更改字节顺序不会更改字节的内部顺序,而只是更改多字节类型(short, int, long)的方式。这两个版本均不对数组进行重新排序,因此可能比进行任何重新排序的速度更快。如果您确实要重新排序,请在线程中查看其他答案。

您可以使用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

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

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

如果您知道如何告诉编译器进行某种循环展开优化,它可能比“常规交换”更快。

本页上列出的方法似乎都不像BitcoinJ source code中的方法那样简单:

/** * Returns a copy of the given byte array in reverse order. */ public static byte[] reverseBytes(byte[] bytes) { // We could use the XOR trick here but it's easier to understand if we don't. If we find this is really a // performance issue the matter can be revisited. byte[] buf = new byte[bytes.length]; for (int i = 0; i < bytes.length; i++) buf[i] = bytes[bytes.length - 1 - i]; return buf; }


2
投票
您可以使用Unsafe进行一些技巧,这些技巧更快,但是最简单的方法是确保代码已预热。

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

0
投票
本页上列出的方法似乎都不像BitcoinJ source code中的方法那样简单:
© www.soinside.com 2019 - 2024. All rights reserved.