有没有办法浅拷贝一个现有的文件对象?

6 投票
1 回答
1539 浏览
提问于 2025-04-27 13:50

这个情况是想要根据某个文件对象创建多个生成器,而不让它们互相干扰各自的读取状态。

最开始我以为我用 seek()tell() 实现了一个可行的方案,每个生成器都被一个元生成器装饰,这个元生成器负责维护文件指针的位置。这个方法在像 StringIO 这样的东西上运行得很好,但在处理真实文件时就失败了,因为读取前的缓存会搞乱 偏移量

使用 readline() 或者其他方式模拟真实的文件对象也不行,因为这样做的原因是文件太大,才需要生成器表达式。所以失去读取前的缓存并不是一个好选择(顺便问一下,为什么Python一开始就是这样设计的?缓存不应该像个缓存一样,而不是直接暴露给用户吗?合理的封装本来应该避免这个 tell() 的问题……)

然后我尝试使用 copy.copy,但结果是这样的:<closed file '<uninitialized file>', mode '<uninitialized file>' at 0x7f722ffda810>。看起来是不可用的。

有没有其他方法可以复制?有没有办法初始化一个文件对象?还是说我应该完全放弃这个用例,因为在Python中根本不可能?

暂无标签

1 个回答

9

你需要用到 itertools.tee 这个工具。

from itertools import tee
with open("somefile.txt", "r") as fh:
    fh1, fh2, fh3 = tee(fh, 3)

一旦你调用了 tee,就不要再使用原来的迭代器了。不过,从 tee 返回的迭代器可以自由独立地使用。

如果是处理文件对象(这样可以保留像 read 这样的文件特定方法),你可以多次打开同一个文件;每个文件对象会保持自己的读取位置。

fh1, fh2, fh3 = [open("somefile.txt") for i in range(3)]

或者,如果你已经有一个文件对象 fh

fh1, fh2, fh3 = [open(fh.name) for i in range(3)]

这样做不会保留已经移动过的文件指针,但跳到后面的位置还是很简单的:

for x in fh1, fh2, fh3:
    x.seek(fh.tell())

撰写回答