防止 BufferedReader 关闭文件列表的文件

发布于 2024-12-22 15:06:14 字数 425 浏览 3 评论 0原文

我有一个扩展 BufferedReader 的类和一个文件流列表 除了最后一个流之外的所有流都调用 b.close() ,我想保持流打开 我该怎么做?

谢谢

class TestReader(BufferedReader):
    pass

def test(streams):
    for stream in streams:
        b=TestReader(stream)
        do_something(b)
    #all the streams except streams[-1] are closed, how do I prevent this?

streams=[open('test1.txt','rb'),open('test2.txt','rb')]
test(streams)
streams.do_something_else()

I have a class which extends BufferedReader, and a list of file streams
b.close() is called for all except the last stream, I want to keep the streams open
How do I do this?

thanks


class TestReader(BufferedReader):
    pass

def test(streams):
    for stream in streams:
        b=TestReader(stream)
        do_something(b)
    #all the streams except streams[-1] are closed, how do I prevent this?

streams=[open('test1.txt','rb'),open('test2.txt','rb')]
test(streams)
streams.do_something_else()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

远昼 2024-12-29 15:06:14

即使在实现中 BufferedIOBase 类包装了 IOBase 对象,它们的接口是一个流(一切都继承自 IOBase ),因此 IOBase 对象的普通行为是在超出范围时关闭自身。 BufferedIOBase 只是将 close() 调用委托给底层流。

您不应该将 BufferedReader 视为流包装器(尽管这就是它的实现方式),而应将其视为现有流的类型转换。两个流完全绑定在一起。但是,您可以使用 detach() 解除包装流的绑定,但这会使 BufferedIOBase 对象变得无用。

此外,当模式为 rb 时,io.open 已经返回一个 BufferedReader,因此您是双缓冲的。您应该使用 io.FileIO 来代替。

您有几个选择:

  1. 创建一个新的流和一个新的底层文件描述符,并传递文件名而不是流。这是最简单、最安全的选项。

  2. 创建原始文件描述符并根据需要从中创建流。这需要一些
    注意多个流不要同时使用相同的文件描述符。例如:

    fd = os.open('test.txt', os.O_RDONLY)
    file1 = FileIO(fd, 'r', closefd=False)
    file2 = FileIO(fd, 'r', closefd=False)
    
    文件1.读取(100)
    断言 file1.tell() == 100
    文件2.读取(100)
    断言 file1.tell() == 200
    
  3. BufferedIOBase 对象关闭其流之前,

    detach() 底层流。 (记得快退流!)

    def 测试(流):
        对于流中的流:
            b=TestReader(流)
            做某事(b)
            包裹流 = b.detach()
            断言wrappedstream是流
    

    您甚至可以在析构函数中实现它:

    类 TestReader(BufferedReader):
        def __del__(自我):
            self.detach()
            # self.raw不会被关闭,
            # 宁愿保持分离时的状态
    

    或者如果您认为语义错误,则完全禁用 close() 委托:

    类 TestReader(BufferedReader):
        def 关闭(自身):
            self.close = True
    

我不知道什么是大局你正在做的(可能你需要不同的设计),但这就是我实现我看到的代码的方式:

from io import FileIO, BufferedReader
import io
import os

class TestReader(BufferedReader):
    pass

def test(streams):
    for stream in streams:
        b = TestReader(stream)

def test_reset(streams):
    """Will try to leave stream state unchanged"""
    for stream in streams:
        pos = stream.tell()
        b = TestReader(stream)
        do_something(b)
        b.detach()
        stream.seek(pos)



filenames = ['test1.txt', 'test2.txt']

# option 1: just make new streams

streams = [FileIO(name, 'r') for name in filenames]
test(streams)
streams = [io.open(name, 'rb') for name in filenames]
#etc


# option 2: use file descriptors
fds = [os.open(name, os.O_RDONLY) for name in filenames]
#closefd = False means "do not close fd on __del__ or __exit__"
#this is only an option when you pass a fd instead of a file name
streams = [FileIO(fd, 'r', closefd=False) for fd in fds]
test(streams)
streams = []
for fd in fds:
    os.lseek(fd, 0, os.SEEK_SET)
    streams.append(io.open(fd, 'rb', closefd=False))
    # you can also .seek(0) on the BufferedReader objects
    # instead of os.lseek on the fds


# option 3: detach

streams = [FileIO(name, 'r') for name in filenames]
test_reset(streams)
# streams[*] should still be in the same state as when you passed it in

Even though in the implementation BufferedIOBase classes wrap an IOBase object, their interface is a stream (everything inherits from IOBase), so the ordinary behavior of a IOBase object is to close themselves when they go out of scope. BufferedIOBase just delegates the close() call to the underlying stream.

You shouldn't view a BufferedReader as a stream wrapper (although that is how it is implemented), but as a type-casting of an existing stream. The state of the two streams is completely bound together. However, you can unbind the wrapped stream with detach(), but this leaves the BufferedIOBase object useless.

Additionally, io.open returns a BufferedReader already when mode is rb, so you are double-buffering. You should use io.FileIO instead.

You have a few choices:

  1. Create a new stream and a new underlying file descriptor, and pass around file names instead of streams. This is your easiest and safest option.

  2. Create raw file descriptors and create streams from them as needed. This requires some
    care that multiple streams are not using the same file descriptor at the same time. For example:

    fd = os.open('test.txt', os.O_RDONLY)
    file1 = FileIO(fd, 'r', closefd=False)
    file2 = FileIO(fd, 'r', closefd=False)
    
    file1.read(100)
    assert file1.tell() == 100
    file2.read(100)
    assert file1.tell() == 200
    
  3. detach() the underlying stream before your BufferedIOBase object closes its stream. (Remember to rewind the stream!)

    def test(streams):
        for stream in streams:
            b=TestReader(stream)
            do_something(b)
            wrappedstream = b.detach()
            assert wrappedstream is stream
    

    You can even implement this in your destructor:

    class TestReader(BufferedReader):
        def __del__(self):
            self.detach()
            # self.raw will not be closed,
            # rather left in the state it was in at detachment
    

    Or just disable close() delegation completely if you think the semantics are wrong:

    class TestReader(BufferedReader):
        def close(self):
            self.closed = True
    

I don't have the big picture of what you are doing (possibly you need a different design), but this is how I would implement the code I see:

from io import FileIO, BufferedReader
import io
import os

class TestReader(BufferedReader):
    pass

def test(streams):
    for stream in streams:
        b = TestReader(stream)

def test_reset(streams):
    """Will try to leave stream state unchanged"""
    for stream in streams:
        pos = stream.tell()
        b = TestReader(stream)
        do_something(b)
        b.detach()
        stream.seek(pos)



filenames = ['test1.txt', 'test2.txt']

# option 1: just make new streams

streams = [FileIO(name, 'r') for name in filenames]
test(streams)
streams = [io.open(name, 'rb') for name in filenames]
#etc


# option 2: use file descriptors
fds = [os.open(name, os.O_RDONLY) for name in filenames]
#closefd = False means "do not close fd on __del__ or __exit__"
#this is only an option when you pass a fd instead of a file name
streams = [FileIO(fd, 'r', closefd=False) for fd in fds]
test(streams)
streams = []
for fd in fds:
    os.lseek(fd, 0, os.SEEK_SET)
    streams.append(io.open(fd, 'rb', closefd=False))
    # you can also .seek(0) on the BufferedReader objects
    # instead of os.lseek on the fds


# option 3: detach

streams = [FileIO(name, 'r') for name in filenames]
test_reset(streams)
# streams[*] should still be in the same state as when you passed it in
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文