0

我正在尝试在 python 中就地编辑文本文件。它非常大(因此不能将其加载到内存中)。我打算替换我在里面找到的逐字节字符串。

with f as open("filename.txt", "r+b"):
    if f.read(8) == "01234567":
        f.seek(-8, 1)
        f.write("87654321")

但是,当我尝试它时, write() 操作会添加到文件的末尾:

>>> n.read()
'sdf'
>>> n.read(1)
''
>>> n.seek(0,0)
>>> n.read(1)
's'
>>> n.read(1)
'd'
>>> n.write("sdf")
>>> n.read(1)
''
>>> n.seek(0,0)
>>> n.read()
'sdfsdf'
`

我希望结果是sdsdf.

4

2 回答 2

1

在将读写模式流从读模​​式切换到写模式时,原始的 ANSI/ISO C 标准要求进行寻道操作,反之亦然。此限制仍然存在,例如,n1570包含以下文本:

当以更新模式打开文件时('+'作为上述模式参数值列表中的第二个或第三个字符),可以在关联的流上执行输入和输出。但是,如果没有对函数fflush或文件定位函数(fseekfsetposrewind输入操作遇到文件结尾。在某些实现中,使用更新模式打开(或创建)文本文件可能会打开(或创建)二进制流。

无论出于何种原因,此限制已被导入 Python,1即使 Python 包装器可以自动处理它。

对于它的价值,最初的 ANSI C 限制的原因是在许多基于 Unix 的系统上发现的低预算实现:它们为每个流保留“当前字节数”和“当前指针”。如果宏化getcputc操作必须调用底层实现,则当前字节数为 0,这可以检查流是否以更新模式打开并根据需要进行切换。但是一旦你成功获得了一个字符,计数器就会保存可以继续从底层流中读取的字符数;一旦你成功地写了一个字符,计数器就会保存允许添加字符的缓冲区位置的数量。

这意味着,如果您成功getc填充了一个内部缓冲区,但后面跟着一个putc,则“写入”字符putc将简单地覆盖缓冲的数据。如果您有一个成功putc但执行不善的getc,您会看到缓冲区中的未设置值。

这个问题很容易解决(只需提供单独的输入和输出计数器,其中一个始终为零,并且还具有为模式切换实现缓冲区重新填充检查的功能)。


1需要引用:-)

于 2015-11-01T00:41:15.357 回答
0

您可以检查以下代码的差异:

>>> f = open("file.txt", "r+b")
>>> f.seek(2)
>>> f.write("sdf")
>>> f.seek(0)
>>> f.read()
'sdsdf'


>>> f = open("file.txt", "r+b")
>>> f.read(1)
's'
>>> f.read(1)
'd'
>>> f.write("sdf")
>>> f.seek(0)
>>> f.read()
'sdfsdf'

.write 的指针最初位于文件末尾。只有 .seek() 会改变它的位置,而不是 .read()。所以你必须在写入字节之前调用 .seek() 。以下代码运行良好:

>>> f = open("file.txt", "r+b")
>>> f.read(1)
's'
>>> f.read(1)
'd'
>>> f.seek(2)
>>> f.write("sdf")
>>> f.seek(0)
>>> f.read()
'sdsdf'
于 2015-11-01T01:03:58.030 回答