字节交换

字节排序和数据数组介绍

这个 ndarray 是为内存中的数据提供Python数组接口的对象。

通常情况下,使用数组查看的内存与运行python的计算机的字节顺序不同。

例如,我可能在一台有一个小endian CPU的计算机上工作,比如英特尔奔腾,但是我已经从一台大endian计算机写的文件中加载了一些数据。假设我已经从Sun(big endian)计算机编写的文件中加载了4个字节。我知道这4个字节代表两个16位整数。在big-endian机器上,两个字节的整数首先存储最有效字节(msb),然后存储最低有效字节(lsb)。因此,字节按内存顺序为:

  1. MSB整数1

  2. LSB整数1

  3. MSB整数2

  4. LSB整数2

假设这两个整数实际上是1和770。因为770=256*3+2,内存中的4个字节将分别包含:0、1、3、2。我从文件中加载的字节将包含以下内容:

>>> big_end_buffer = bytearray([0,1,3,2])
>>> big_end_buffer
bytearray(b'\\x00\\x01\\x03\\x02')

我们可能想使用 ndarray 访问这些整数。在这种情况下,我们可以围绕这个内存创建一个数组,并告诉numpy有两个整数,它们是16位和big-endian:

>>> import numpy as np
>>> big_end_arr = np.ndarray(shape=(2,),dtype='>i2', buffer=big_end_buffer)
>>> big_end_arr[0]
1
>>> big_end_arr[1]
770

注意数组 dtype 以上 >i2 . 这个 > 意思是“big endian” (< 是小endian)和 i2 表示“有符号2字节整数”。例如,如果我们的数据表示一个单无符号的4字节小尾数整数,那么dtype字符串将是 <u4 .

事实上,我们为什么不试试呢?

>>> little_end_u4 = np.ndarray(shape=(1,),dtype='<u4', buffer=big_end_buffer)
>>> little_end_u4[0] == 1 * 256**1 + 3 * 256**2 + 2 * 256**3
True

回到我们的 big_end_arr -在这种情况下,我们的基础数据是big endian(数据endianness),我们已经将dtype设置为匹配(dtype也是big endian)。然而,有时你需要把这些翻过来。

警告

scalar当前不包含字节顺序信息,因此从数组中提取标量将返回本机字节顺序的整数。因此:

>>> big_end_arr[0].dtype.byteorder == little_end_u4[0].dtype.byteorder
True

更改字节顺序

正如您从介绍中可以想象到的,有两种方法可以影响数组的字节顺序和它所查看的底层内存之间的关系:

  • 更改数组数据类型中的字节顺序信息,以便将基础数据解释为不同的字节顺序。这是 arr.newbyteorder()

  • 更改基础数据的字节顺序,使数据类型解释保持原样。这是什么 arr.byteswap() 做。

需要更改字节顺序的常见情况是:

  1. 您的数据和DTYPE结束符不匹配,您希望更改DTYPE,使其与数据匹配。

  2. 您的数据和DTYPE结束符不匹配,您希望交换数据,以便它们与DTYPE匹配。

  3. 您的数据和DTYPE端序匹配,但您希望交换的数据和DTYPE反映这一点。

数据和DTYPE ENDIANNESS不匹配,请更改DTYPE以匹配数据

我们做了一些不匹配的事情:

>>> wrong_end_dtype_arr = np.ndarray(shape=(2,),dtype='<i2', buffer=big_end_buffer)
>>> wrong_end_dtype_arr[0]
256

对于这种情况,最明显的解决方法是更改数据类型,使其具有正确的结束方式:

>>> fixed_end_dtype_arr = wrong_end_dtype_arr.newbyteorder()
>>> fixed_end_dtype_arr[0]
1

注意,数组在内存中没有更改:

>>> fixed_end_dtype_arr.tobytes() == big_end_buffer
True

数据和类型结尾不匹配,请更改数据以匹配数据类型

如果您需要内存中的数据进行某种排序,那么您可能需要这样做。例如,您可能正在将内存写到需要特定字节顺序的文件中。

>>> fixed_end_mem_arr = wrong_end_dtype_arr.byteswap()
>>> fixed_end_mem_arr[0]
1

现在数组 has 内存已更改:

>>> fixed_end_mem_arr.tobytes() == big_end_buffer
False

数据和数据类型的端序匹配、交换数据和数据类型

您可能有一个正确指定的数组数据类型,但您需要该数组在内存中具有相反的字节顺序,并且您希望该数据类型匹配,这样数组值才有意义。在这种情况下,您只需执行前面的两个操作:

>>> swapped_end_arr = big_end_arr.byteswap().newbyteorder()
>>> swapped_end_arr[0]
1
>>> swapped_end_arr.tobytes() == big_end_buffer
False

使用ndarray-astype方法可以实现将数据强制转换为特定数据类型和字节顺序的更简单方法:

>>> swapped_end_arr = big_end_arr.astype('<i2')
>>> swapped_end_arr[0]
1
>>> swapped_end_arr.tobytes() == big_end_buffer
False