我正在使用一种工具为项目生成虚拟二进制文件。我们有一个描述真实二进制文件的规范,该二进制文件是由具有不同位长的值流创建的。我使用输入文件和规范文件来创建值列表,并使用bitstring
库的BitArray
类来转换值并将它们连接在一起。
问题在于值的长度并不总等于完整字节,我需要文件按原样包含位。通常我可以使用BitArray.tofile()
,但是该方法会自动在文件末尾填充零。
还有另一种方法将位写入文件吗?
答案 0 :(得分:3)
显然,原始二进制文件只能存储字节,即8位的倍数。
当您需要存储数据(位)和元数据(关于数据的数据,在这种情况下,长度为位)时,有两种方法:
选择或发明一种文件格式,例如具有长度和十六进制转储的JSON结构(不节省空间,仅是示例):
{
"length": 11,
"data": "c3a"
}
使用sidecar file文件存储元数据。这不太常见。
答案 1 :(得分:1)
在大多数操作系统中,文件都包含字节流,有时也称为字符。在某些系统中,文本存储和二进制数据存储之间存在差异(例如PDP-1使用6位字符和18位字),但是文件大小以这些字节为单位。对于某些系统,甚至不存储该级别,但文件末尾字符用于标记数据在最后一个块(扇区,簇或范围)中的结束位置。
您将需要复制这些方法之一来存储许多位,例如使用1-then-0s padding。该填充方法的缺点是您需要找到结尾以了解是否由0(和前一个1)组成的字符串构成了填充,而不是数据。
另一种方法可能是先存储位数,或者仅存储每个已写入块的位数。这样做需要一种编码,以便您知道size字段的大小,例如一个字节,这意味着不超过256位的块。例如,使用该长度前缀方法。在Pascal strings中。
您可能还想考虑存储位序列的已建立文件格式,例如serial vector format。其中大多数效率不是很高,并且是为特定任务而设计的(在这种情况下,是存储电路仿真的时间序列)。
诸如此类的方案也可以概括为数据存储格式本身。示例包括length-prefixed strings,UTF-8 code points,BitTorrent Bencoding或Exponential-Golomb coding。今天的最后一个是有意义的,因为它允许任意大小并且由bitstring模块支持。
位串中一种相当简单的方法可能是在文件中添加一个(对齐的)尾随字节,以表明倒数第二个字节中有多少位被填充:
def pad(data: bitstring.BitArray):
padding = data.bytealign()
data.append(bitstring.Bits(chr(padding)))
def unpad(data: bitstring.BitArray):
padding = data[-8:].uint
del data[-8-padding:]
如果您要逐个读取文件,则必须注意在到达最后两个字节时进行此填充。
这里是1到0的变体:
def pad(data: bitstring.BitArray):
data.append(bitstring.Bits(length=1, uint=1))
data.bytealign()
def unpad(data: bitstring.BitArray):
last1 = data.rfind(bitstring.Bits(length=1, uint=1))[0]
del data[last1:]
答案 2 :(得分:0)
您需要对7位值进行填充,使其与整个字节数匹配:
1010101
(7位)-> 01010101
1111
(4位)-> 00001111
最高有效数字的填充不会影响从文件中获取的数据。