Python - 将文件内容转换为二进制数组

11

文件内容:

40 13 123
89 123 2223
4  12  0

我需要将整个 .txt 文件存储为二进制数组,以便稍后将其发送到服务器端,服务器期望一个二进制输入。


我查看了 Python 的 bytearray 文档。其中一段引用如下:

返回一个由字节组成的新数组。bytearray 类型是一个可变序列,包含在 0 <= x < 256 范围内的整数。它具有大多数常规可变序列的方法,详见可变序列类型描述,也拥有 bytes 类型具备的大部分方法,详见 Bytes 和 Byte Array 方法。


但我的数字大于 256,我需要一个适用于大于 256 的数字的 bytearray 数据结构。


你的意思是要将文本表示存储为 int32 数组吗? - xtofl
1
@xtofl 是的。但我的问题是,我想把每个数字转换成二进制对象?如果我访问第一行,我会得到第一个数字的二进制表示。 - Tony
1
你有具体想要的示例吗?"101010"不是二进制对象,它是代表二进制中的42的字符串。作为整数的42已经以二进制形式存储在Python中了。 - Eric Duminil
1
@EricDuminil 是的先生,对不起我的解释不好。一个字节是8位,可以作为“二进制”数据发送。我需要有一个二进制数字序列,以便我知道何时停止阅读以了解我的第一个数字、第二个数字等等。一种方法是像xtofl所说的那样用32位表示。但是我无法使bytearray存储超过8位的任何数字,因为大于256的任何数字都无法存储。 - Tony
1
那就使用一个整型数组,然后完成它。服务器难道不是明确指定了它期望的格式吗? - Eric Duminil
@EricDuminil 服务器确实指定了:void func(1:binary message),其中 binary 在 Thrift 类型中表示字节数组。 - Tony
5个回答

8
你可以使用 array/memoryview 方法。
import array
a = array.array('h', [10, 20, 300]) #assume that the input are short signed integers
memv = memoryview(a)
m = memv.cast('b') #cast to bytes
m.tolist()

这将得到[10, 0, 20, 0, 44, 1]

根据使用情况,也可以进行以下操作:

L = array.array('h', [10, 20, 300]).tostring()
list(map(ord, list(L)))

这也会返回 [10, 0, 20, 0, 44, 1]


不错!我看到还有array.from_list(...) - xtofl
类型错误:无法创建内存视图,因为对象没有缓冲区接口。我读到了array.array对象仅在Python 3上支持此功能?https://dev59.com/hVPTa4cB1Zd3GeqPn_Zt - Tony
2
@xtofl 它在 Python 3 上运行良好,但不幸的是,在 Python 2.7 上似乎不支持对数组应用 memoryview - http://bugs.python.org/issue17145 - ewcz
@TonyTannous然后我只需要将'h'更改为'd',即用整数替换短整数... - ewcz
@TonyTannous 你可以像这样构建一个:bytearray(array.array('b', [10, 20, 30]).tostring()) - ewcz
显示剩余3条评论

3
您可以读取文本文件并将每个“单词”转换为整数:
with open(the_file, 'r') as f:
    lines = f.read_lines()
    numbers = [int(w) for line in lines for w in line.split()]

接下来你需要使用structnumbers打包成二进制数组:

binary_representation = struct.pack("{}i".format(len(numbers)), *numbers)

如果您想将这些数据以二进制格式写入,打开目标文件时必须进行指定:

with open(target_file, 'wb') as f:
   f.write(binary_representation)

我同意这种双重列表推导语法更易读,但不幸的是它不起作用。此外,如果你在一个字符串上迭代,你得到的是字符而不是单词。 - Eric Duminil
出错了。反过来了。谢谢。 - xtofl

2

非bytearray

根据bytearray文档,它只是一个整数序列,范围在0 <= x < 256之间。

例如,您可以像这样初始化它:

bytearray([40,13,123,89,123,4,12,0])
# bytearray(b'(\r{Y{\x04\x0c\x00')

由于整数已经以二进制形式存储,因此您不需要进行任何转换。

现在您面临的问题是:您想对 2223 做什么?

>>> bytearray([2223])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: byte must be in range(0, 256)

使用uint32还是int32数组?

如果要读取一个文件,可以使用以下代码:

import re
with open('test.txt') as f:
    numbers = [int(w) for line in f for w in re.split(' +', line)]
    print numbers
    #[40, 13, 123, 89, 123, 2223, 4, 12, 0]

如果你已经有一个整数列表,那么你可以选择相应的低级Numpy数据结构,可能是uint32int32


1
我需要这个服务器-客户端模块,其中一个函数需要binary输入。不同的thrift类型可以在here找到。 客户端
myList = [5, 999, 430, 0]
binL = array.array('l', myList).tostring()
# call function with binL as parameter

在服务器端,我重构了列表。
k = list(array.array('l', binL))
print(k)
[5, 999, 430, 0]

0

试试这个:

input.txt:

40 13 123
89 123 2223
4  12  0

将输入解析为输出的代码:

with open('input.txt', 'r') as _in:
    nums = map(bin, map(int, _in.read().split())) # read in the whole file, split it into a list of strings, then convert to integer, the convert to binary string

with open('output.txt', 'w') as out:
          out.writelines(map(lambda b: b + '\n', map(lambda n: n.replace('0b', ''), nums))) # remove the `0b` head from the binstrings, then append `\n` to every string in the list, then write to file

output.txt:

101000
1101
1111011
1011001
1111011
100010101111
100
1100
0

希望能有所帮助。


谢谢,但我不想将它作为二进制写入新文件,我需要将其保存在二进制对象中,比如字节数组等。但我感激你的努力。谢谢。 - Tony
@TonyTannous:那么你的问题就没有意义了,看起来你不知道自己想要发送什么。 - Eric Duminil
1
@EricDuminil他知道,但没有适当的术语来表达。 - xtofl
1
@TonyTannous 然后只需使用一个 int 列表。稍后您可以将其转换为任何您想要的类型 :D - Szabolcs

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