Python,如何将32位整数放入字节数组中

8

我通常会在C++中执行这样的操作,但我正在使用Python编写一个快速脚本,遇到了难题。

如果我有一个二进制列表(或者是Python存储“fread”结果的任何东西),我可以用以下方式访问其中的单个字节:buffer[0]、buffer[1]等。

我需要更改字节[8-11]以保存新的32位文件大小(即:已经有一个文件大小,我需要更新它)。在C++中,我只需获取指向该位置的指针并将其强制转换为整数类型来存储,但是在Python中,我突然意识到我不知道如何做这样的事情。

在Python中,我如何将缓冲区中特定位置的4个字节更新为整数值?

编辑

我要补充一些信息,因为似乎从解决方案中无法找到答案(尽管我可以看出它们的思路正确)。

首先,我使用的是Python 2.4(无法升级,因为是大公司的服务器),所以我的选择显然受到限制。抱歉之前没有提到,我不知道它的功能有这么少。

其次,让我们简化问题。

假设我有一个名为“myfile.binary”的二进制文件,其中包含五个字节的内容“4C53535353”(十六进制表示),这相当于文件中仅有字母“L和4个S”的ASCII表示。

如果我执行以下操作:

f = open('myfile.binary', 'rb')
contents = f.read(5)

根据Sven Marnach的回答,contents应该是一个由五个不可变的字节字符串组成的。

仅使用Python 2.4的工具,我如何将'contents'中持有的4个'S'更改为任意整数值?也就是说,给我一行代码,可以使字节索引内容[1-4]包含32位整数'myint',其值为12345678910。


由于字符串是不可变的,因此您无法更改其内容...您可以创建一个新字符串,或使用像bytearray这样的可变容器。 - hochl
谢谢,如果需要的话,我很乐意创建一个新的字符串或字节数组。我该如何创建一个可修改的字节数组,并将其范围[1-4]更新为等于我的整数的二进制表示? - John Humphreys
我在下面扩展了我的帖子,并包括了Python 2.4的工作示例 :-) - hochl
5个回答

11
您需要的是这个函数:
struct.pack_into(fmt, buffer, offset, v1, v2, ...)

这些内容的文档可以在http://docs.python.org/library/struct.html的顶部找到。

示例代码:

import struct
import ctypes

data=ctypes.create_string_buffer(10)
struct.pack_into(">i", data, 5, 0x12345678)
print list(data)

相关帖子:Python: 如何使用struct.pack_into将不同类型的数据打包到字符串缓冲区中

编辑:添加了一个适用于Python 2.4的示例:

import struct

f=open('myfile.binary', 'rb')
contents=f.read(5)
data=list(contents)
data[0:4]=struct.pack(">i", 0x12345678)
print data

1
+1. 我建议使用内置的 bytearray 来创建可变缓冲区,而不是使用 ctypes.create_string_buffer - Sven Marnach
对于每个人,我尝试通过阅读包页面和提供的解决方案来解决它。由于我使用的是Python 2.4而不是2.5,所以似乎我错过了很多东西。我在上面的帖子中提供了一个大大简化版本的问题 - 如果您能用一行代码回答它,我将完全满意 :) - John Humphreys
1
很抱歉,您的2.4兼容版本无法使用bytearray,因为它是在2.6中引入的。 - Scott Griffiths
嗯,没错,我只是避免了pack_into函数...有点尴尬。让我们看看2.4中有什么 :) - hochl
好的,我认为现在它可以工作了,在Python 2.4的虚拟机上尝试过了。还有其他反对意见吗? - hochl

4
请查看Struct模块(http://docs.python.org/library/struct.html)。您需要使用pack函数。

编辑:

代码:

import struct

s = "LSSSS" # your string
s = s[0] + struct.pack('<I', 1234567891) # note "shorter" constant than in your example
print s

输出:

L╙☻ЦI

struct.pack 应该在 Python2.4 中可用。

你的数字 "12345678910" 无法被打包成 4 字节,我缩短了一点。


请看 hochl 答案上的评论。 - John Humphreys

2
file.read() 的结果是 Python 中的字符串,它是不可变的。根据您要完成的任务的上下文,有不同的解决方案。

其中之一是使用array模块:直接将文件读取为32位整数数组。您可以修改此数组并将其写回文件中。

with open("filename") as f:
    f.seek(0, 2)
    size = f.tell()
    f.seek(0)
    data = array.array("i")
    assert data.itemsize == 4
    data.fromfile(f, size // 4)
data[2] = new_value
# use data.tofile(g) to write the data back to a new file g

1
请参阅hochl答案上的评论。 - John Humphreys

2

您可以安装numpy模块,这个模块通常用于科学计算。

read_data = numpy.fromfile(file=id, dtype=numpy.uint32)

然后访问所需位置的数据并进行更改。


1
请参见hochl答案的评论。 - John Humphreys

1
以下只是一个演示,让您了解当四个字节转换为整数时发生的实际情况。 假设你有一个数字:15213
Decimal: 15213
Binary: 0011 1011 0110 1101
Hex: 3 B 6 D

在小端系统中(如x86机器),可以使用长度为4的字节数组表示该数字:b"\x6d\x3b\x00\x00"b"m;\x00\x00"。当您在屏幕上打印它时,要将这四个字节转换为整数,我们只需进行一些基本转换,即:

sum(n*(256**i) for i,n in enumerate(b"\x6d\x3b\x00\x00"))

这会给你结果:15213。

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