写入文件并不太难,看起来很简单:
并不像你想象的那么简单。尝试查看文件中的内容,或者只是打印出您正在编写的内容:
>>> struct.pack('<s', 'myapp-0.0.1')
'm'
正如文档解释的那样:
对于's'
格式字符,计数被解释为字符串的大小,而不是像其他格式字符那样的重复计数;例如,'10s'
表示单个 10 字节字符串,而'10c'
表示 10 个字符。如果未给出计数,则默认为 1。
那么,您如何处理呢?
struct
如果不是您想要的,请不要使用。使用的主要原因是与将 C对象直接转储到缓冲区/文件/套接字/任何东西或以类似样式(例如 IP 标头)编写的二进制格式规范的struct
C 代码进行交互。struct
它不适用于 Python 数据的一般序列化。正如 Jon Clements 在评论中指出的那样,如果您只想存储一个字符串,那么只需write
按原样存储字符串即可。如果要存储更复杂的东西,请考虑json
模块;如果您想要更灵活、更强大的功能,请使用pickle
.
使用固定长度的字符串。如果您的文件格式规范的一部分是名称必须始终为 255 个字符或更少,只需编写'<255s'
. 较短的字符串将被填充,较长的字符串将被截断(您可能需要检查以引发异常而不是静默截断)。
使用一些带内或带外方式沿长度传递。最常见的是长度前缀。(您可能可以使用'p'
or'P'
格式来提供帮助,但这实际上取决于您尝试匹配的 C 布局/二进制格式;通常您必须做一些丑陋的事情,例如struct.pack('<h{}s'.format(len(name)), len(name), name)
.)
至于为什么您的代码失败,有多种原因。首先,read(11)
不能保证读取 11 个字符。如果文件中只有 1 个字符,这就是你得到的全部。其次,您实际上并不是在调用read(11)
,而是在调用read(1)
,因为struct.calcsize('s')
返回1
(原因从上面应该很明显)。第三,要么您的代码与上面显示的不完全一致,要么infile
' 文件指针不在正确的位置,因为编写的代码将成功读取字符串'm'
并将其解压缩为'm'
. (我在这里假设 Python 2.x;3.x 会有更多问题,但你甚至不会走那么远。)
对于您的特定用例(“文件头......包含有关内容的信息;版本信息和其他字符串值”),我只使用write
带有换行符终止符的字符串。(如果字符串可以嵌入换行符,您可以将它们反斜杠转义为\n
,使用 C 风格或 RFC822 风格的延续,引用它们等)
这有许多优点。一方面,它使格式易于人类阅读(并且人类可编辑/可调试)。而且,虽然有时会带来空间折衷,但单字符终止符至少与长度前缀格式一样有效,甚至可能更高。而且,最后但同样重要的是,这意味着代码对于生成和解析标头都非常简单。
在稍后的评论中,您澄清说您也想编写整数,但这并没有改变任何东西。一个'i'
int 值将占用 4 个字节,但大多数应用程序会写入很多小数字,如果将它们写为字符串,则仅占用 1-2 个字节(终止符/分隔符 +1)。如果你不是在写小数字,Pythonint
很容易太大而无法容纳在 Cint
中——在这种情况下,struct
会默默地溢出,只写低 32 位。