2011-12-25 157 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