2011-12-25 160 views
1

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

感谢

 

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() 

+0

实际上,在您的评论出现的位置,流仍处于打开状态。 – 2011-12-25 20:09:50

+0

不,他们不是,尝试做流[0] .read() – simonzack 2011-12-25 20:12:01

+0

嗯,你是对的,我在我的测试脚本中有一个错误。 – 2011-12-25 20:17:09

回答

4

即使在实施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) 
    
    file1.read(100) 
    assert file1.tell() == 100 
    file2.read(100) 
    assert file1.tell() == 200 
    
  3. detach()底层流的BufferedIOBase对象之前关闭其流。 (记住,倒转流!)

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

    你甚至可以在你的析构函数实现这一点:

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

    或者只是禁用close()代表团完全,如果你认为语义是错误的:

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

我不知道你在做什么(可能你需要一个不同的des ign),但这是我将如何实现我看到的代码:

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 
+0

我确实想在他们之后做些什么,经过测试()之后,有没有办法解决这个问题?我知道这些数据流没有被引用,因此被删除,但创建一个新列表会增加内存使用量(我有很多数据流) – simonzack 2011-12-25 20:12:13

+0

这不是问题。 “BufferedReader”似乎在对引用丢失时关闭流;保持列表中的流不妨碍他们关闭。 – 2011-12-25 20:17:30

+0

但它做到这一点我需要添加一个无用的参数来测试(),所以列表不被推定 – simonzack 2011-12-25 20:51:31