如何在Python中进行32位整数的字节交换?

31

以这个例子为例:

i = 0x12345678
print("{:08x}".format(i))
   # shows 12345678
i = swap32(i)
print("{:08x}".format(i))
   # should print 78563412

如何编写swap32-function()函数?有没有一种在Python中用内置工具进行int字节交换的方法?


4
或者,如果你首先将数字转换为字节数组,可以使用 array.byteswap() 方法。 - aruisdante
3
我找到了这个问题,但它的标题与提问者所要求的内容不符...我修改了它的标题。 - Patrick B.
你的例子是交换了4位二进制块的顺序,而不是字节。如果你交换四个字节的顺序 { 12 34 56 78 },它将变成 { 78 56 34 12 } - AaronF
@AaronF 什么?你的“it would be”正是我在评论中写的。 - Patrick B.
我的错。我误读成了87654321。对此很抱歉。你是正确的。 - AaronF
5个回答

34

一种方法是使用struct模块:

def swap32(i):
    return struct.unpack("<I", struct.pack(">I", i))[0]

首先,您需要使用某种字节序将整数打包为二进制格式,然后使用另一种字节序对其进行解包(甚至无论您使用哪种组合,因为您只想交换字节序)。


swap32(12345678) 的结果应该是什么? - Shahriar
哦,我明白了。谢谢。 - Shahriar
1
@AerofoilKite 要小心,不要被 {:08x} 的输出所迷惑,它省略了 0x。12345678 != 0x12345678。 - Patrick B.
3
@Carsten,“i”格式在函数pack和unpack中表示有符号整数。因此,像0x87654321这样的值在您的定义中处理不好。要将值视为无符号值,可以使用格式“I”:struct.unpack("<I", struct.pack(">I", i))[0] - Artem Zankovich
@ArtemZankovich 谢谢!我忘记了。我已经相应地更新了我的答案。 - Carsten

31

大端字节序指的是32位整数的布局方式,最高有效字节排在第一位,

例如: 0x12345678 的存储布局为

msb             lsb
+------------------+
| 12 | 34 | 56 | 78|
+------------------+

当使用小端序时,内存布局如下:

lsb             msb
+------------------+
| 78 | 56 | 34 | 12|
+------------------+

所以您可以通过一些位掩码和移位来在它们之间进行转换:

def swap32(x):
    return (((x << 24) & 0xFF000000) |
            ((x <<  8) & 0x00FF0000) |
            ((x >>  8) & 0x0000FF00) |
            ((x >> 24) & 0x000000FF))

我会这样做,但它并没有使用“内置”的功能,这就是为什么我接受了其他答案的原因。 - Patrick B.
12
按位移位、或运算和与运算是最基本的操作之一。 - Michael Leonard

18

从Python 3.2开始,您可以将函数swap32()定义为以下内容:

在Python 3.2及以上版本中,可以按照以下方式定义swap32()函数:

def swap32(x):
    return int.from_bytes(x.to_bytes(4, byteorder='little'), byteorder='big', signed=False)

它使用字节数组来表示这个值,并通过在转换回整数时改变字节序来反转字节的顺序。


1
不错!还可以轻松地修改为64位整数。 - Andriy Makukha

3
也许更简单的方式是使用socket库。
from socket import htonl

swapped = htonl (i)
print (hex(swapped))

就是这样。这个库还可以通过ntohl在另一个方向上工作。


3
错误,这在大端系统上不起作用。这就是 htonl 的全部意义所在。 - Glenn Maynard

1

Array 模块提供了一个 byteswap() 方法,用于固定大小的项目。 该数组模块似乎在 Python 2.7 版本中就已经存在了。

array.byteswap() “Byteswap” 数组的所有项目。这仅支持大小为 1、2、4 或 8 字节的值;

除了 fromfile()tofile() 方法外,该模块非常容易使用:

import array

# Open a data file.
input_file = open( 'my_data_file.bin' , 'rb' )

# Create an empty array of unsigned 4-byte integers.
all_data = array.array( 'L' )

# Read all the data from the file.
all_data.fromfile( input_file , 16000 )               # assumes the size of the file

# Swap the bytes in all the data items.
all_data.byteswap( )

# Write all the data to a new file.
output_file = open( filename[:-4] + '.new' , 'wb' )    # assumes a three letter extension
all_data.tofile( output_file )

# Close the files.
input_file.close( )
output_file_close( )

上述代码对我有用,因为我有固定大小的数据文件。有更多Pythonic的方法来处理可变长度的文件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接