2013-09-26 68 views
3

我有一個程序,我需要保留一些打開磁盤列表上的文件的對象,並在程序完成後刪除這些文件。不過,即使沒有更多的引用應該打開它的對象,Python似乎仍然保持打開文件。我已經能夠重現問題與純文件對象如下:Python是否保留對在列表中打開的文件的引用?

import os 

filenames = ['a.txt', 'b.txt'] 
files = [open(f,'w') for f in filenames] 
for f_object in files: 
    f_object.write("test") 

del files[:] 

for name in filenames: 
    os.remove(name) 

當我在Windows上運行此我得到的錯誤

Traceback (most recent call last): 
    File ".\file_del.py", line 11, in <module> 
    os.remove(name) 
WindowsError: [Error 32] The process cannot access the file because it is being used by another process: 'b.txt' 

有趣的是它能夠刪除a.txt沒有問題。即使引用該文件不存在,導致b.txt文件被打開的原因是什麼?

更新

在原來的問題,我沒有訪問到文件關閉它們。相信我,我很想關閉這些文件。請參閱以下內容:

base_uri = 'dem' 
out_uri = 'foo.tif' 
new_raster_from_base_uri(base_uri, out_uri, 'GTiff', -1, gdal.GDT_Float32) 

ds = [] 
for filename in [out_uri]: 
    ds.append(gdal.Open(filename, gdal.GA_Update)) 
band_list = [dataset.GetRasterBand(1) for dataset in ds] 
for band in band_list: 
    for row_index in xrange(band.YSize): 
     a = numpy.zeros((1, band.XSize)) 
     band.WriteArray(a, 0, row_index) 

for index in range(len(ds)): 
    band_list[index] = None 
    ds[index] = None 

del ds[:] 

os.remove(out_uri) 

更新2

我標誌着millimoose的回答如下正確的,因爲它修復該問題與我這裏介紹文件的抽象問題。不幸的是,它不適用於我使用的GDAL對象。爲了將來的參考,我深入挖掘並找到了未記錄的gdal.Dataset.__destroy_swig__(ds)函數,這似乎至少關閉了與數據集關聯的文件。在刪除與數據集關聯的磁盤上的文件之前,我先調用它,並且似乎正常工作。

+0

你有沒有...關閉文件? – Brian

+0

我在這裏抽象了問題,在原始問題中,我從GDAL庫創建GIS數據集。我無權訪問GDAL對象引用的文件。引用計數是相同的。 – Rich

+0

@Brian當對象被GCed時應該關閉文件。 – millimoose

回答

4

循環變量f_object的範圍實際上是周圍的函數/模塊。這意味着即使您清除列表,它仍會保留對迭代中最後一個文件的引用。以下工作正常:

import os 

filenames = ['a.txt', 'b.txt'] 
files = [open(f,'w') for f in filenames] 
for f_object in files: 
    f_object.write("test") 

del files[:] 
# Nuke the last reference. 
del f_object 

for name in filenames: 
    os.remove(name) 

我想你的原始代碼將是del band。或者,移動循環到一個函數,以避免循環變量泄漏:

import os 

def write_to_files(files): 
    for f_object in files: 
     f_object.write("test") 

filenames = ['a.txt', 'b.txt'] 
files = [open(f,'w') for f in filenames] 
write_to_files(files) 

del files[:] 

for name in filenames: 
    os.remove(name) 
0

,你必須關閉文件

for f_object in files: 
    f_object.write("test") 
    f_object.close() 
+0

在我原來的問題中,我沒有訪問該文件來關閉它。但是,一旦引用計數變爲0,Python應該關閉這些文件。我不明白爲什麼上述問題沒有發生。 – Rich

+0

見:http://stackoverflow.com/questions/1834556/does-a-file-object-automatically-close-when-its-reference-count-hits-zero – prgao

1

您需要與file.close()方法關閉文件。當垃圾收集器運行時,文件會自動關閉,但是當這種情況發生時是非確定性的。

確保文件會即使在異常的臉確定性關閉的首選方法是使用with語句上下文管理器:

with open('filename') as f: 
    # Do file operations on f 
    ... 

# At this scope, f is now closed, even if an exception was thrown 

如果你在Python 2.5中,你必須在開始寫from __future__ import with_statement你的程序;如果你使用的是Python 2.6或更高版本,那麼這不是必需的。

+0

這並沒有真正解決微妙古怪的OP是觀察。 'file .__ del __()'應該關閉文件,但由於某種原因,最後打開的文件永遠不會被刪除。 – millimoose

3

Millimoose是正確的,f_object仍持有到列表中的最後一個文件的引用。您只需重置或刪除該變量。我遇到了很多比較奇怪的情況,過去這些情況引用莫名其妙。下面是一個可以用來測試所有引用是否被垃圾收集的方法。請注意,這種使用weakref的方法如果您嘗試從IPython中使用它,將會導致頭痛。

#!/bin/env python 

import weakref 
from sys import getrefcount 

#Open two lists of files 
f1 = [file('temp1.txt','w'), file('temp2.txt','w')] 
f2 = [file('temp3.txt','w'), file('temp4.txt','w')] 

#Loop over both to create arrays of weak references 
weak_f1 = [weakref.ref(x) for x in f1] 
weak_f2 = [weakref.ref(x) for x in f2] 

#Note that x still contains a reference to f2[1] 
print x 

#Print the number of references for each file 
print 'Note, temp4.txt has an extra reference.' 
print 'temp1.txt ref count == %r' % getrefcount(weak_f1[0]()) 
print 'temp2.txt ref count == %r' % getrefcount(weak_f1[1]()) 
print 'temp3.txt ref count == %r' % getrefcount(weak_f2[0]()) 
print 'temp4.txt ref count == %r\n' % getrefcount(weak_f2[1]()) 

#Delete both arrays 
print 'Deleting arrays.' 
del f1[:] 
del f2[:] 

#Print the number of references again 
print 'temp1.txt ref count == %r' % getrefcount(weak_f1[0]()) 
print 'temp2.txt ref count == %r' % getrefcount(weak_f1[1]()) 
print 'temp3.txt ref count == %r' % getrefcount(weak_f2[0]()) 
print 'temp4.txt ref count == %r\n' % getrefcount(weak_f2[1]()) 

#Note, temp4.txt still has two references while the others show MANY references 
#This is because a reference to temp4.txt still exists in `x`. 
#The the other files show many references because they are now pointed at `None`. 
print 'All weak refs are now dead except the one still stored in `x`' 
print weak_f1 
print weak_f2, '\n' 

#Delete `x` and this extra reference is gone 
print 'Deleting `x`' 
del x 

#All references are now `None` 
print 'Now we have lost our last file reference and all weakrefs are dead' 
print weak_f1 
print weak_f2 
+2

是的,**從來沒有**依靠'德爾'被調用。我們有一個理由。 – Veedrac

+0

是的,我可以在那裏同意。 – Vorticity

相關問題