我正在寻找一种干净简单的方法来从Python中的文件或类文件对象中读取以null结尾的C字符串。以一种不会从文件中消耗更多输入的方式,或者将其推回到它所使用的任何文件/缓冲区,以便其他代码可以在以null结尾的字符串之后立即读取数据。
我已经看过a bit of rather ugly code这样做了,但我想用的并不多。
universal newlines support仅适用于open()
ed文件,而不适用于StringIO对象等,并且看起来不像处理非常规换行符。此外,如果它确实有效,则会导致附加\n
的字符串,这是不可取的。
struct doesn't look like it supports reading arbitrary-length C strings at all,要求长度作为格式的一部分。
ctypes有c_buffer
,可以从字节字符串构造,并将第一个以空字符结尾的字符串作为其value
返回。同样,这需要确定必须提前读取多少,并且它不区分空终止和未终止的字符串。 c_char_p
也是如此。所以它似乎没什么帮助,因为你已经知道你已经阅读了足够多的字符串并且必须处理缓冲区分裂。
在C中执行此操作的常用方法是将块读取到缓冲区中,如果需要,复制并调整缓冲区大小,然后检查最新的块读取是否包含空字节。如果是这样,将所有内容返回到空字节并重新对齐缓冲区,或者如果您正在寻找,请继续阅读并将其用作环形缓冲区。 (这只有在您将多余的数据读回给调用者时,或者当您的平台ungetc
允许将大量数据推回到文件中时才有效。)
是否有必要在Python中拼出类似的代码?我很惊讶在io
,ctypes
或struct
找不到任何内容。
文件对象似乎无法回到缓冲区,如ungetc
,并且io
模块中的缓冲I / O流也没有。
我觉得我必须错过这里显而易见的事实。我真的宁愿避免逐字节读取:
def readcstr(f):
buf = bytearray()
while True:
b = f.read(1)
if b is None or b == '\0':
return str(buf)
else:
buf.append(b)
但是现在我正在做的事情。
答案 0 :(得分:4)
令人难以置信的轻微改进(主要是因为它使用了更多的内置函数,在CPython中,在C中实现,通常运行得更快):
import functools
import itertools
def readcstr(f):
toeof = iter(functools.partial(f.read, 1), '')
return ''.join(itertools.takewhile('\0'.__ne__, toeof))
这是相对丑陋的(并且对文件对象的类型敏感;它不会使用返回unicode
的文件对象),而是将所有工作推送到C层。两个arg iter确保您在文件耗尽时停止,而itertools.takewhile
查找(并使用)NUL
终结符但不会更多; ''.join
然后将读取的字节组合成单个返回值。