3

我有一个程序,我需要在磁盘列表中保留一些打开文件的对象,并在程序完成后删除这些文件。然而,即使没有更多对应该打开文件的对象的引用,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)似乎至少关闭了与数据集关联的文件的未记录函数。在删除与数据集关联的磁盘上的文件之前,我首先调用它,这似乎有效。

4

4 回答 4

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)
于 2013-09-26T22:38:24.367 回答
3

Millimoose 是正确的,f_object它仍然持有对列表中最后一个文件的引用。您只需要重置或删除该变量。我遇到过更奇怪的情况,在过去,引用被莫名其妙地保留了下来。下面是一个可以用来测试所有引用是否都被垃圾回收的方法。请注意,如果您尝试在 IPython 中使用 s,这种使用weakrefs 的方法会让您头疼不已。

#!/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
于 2013-09-26T23:10:26.573 回答
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 或更高版本,则没有必要。

于 2013-09-26T22:31:41.740 回答
0

你必须关闭文件

for f_object in files:
    f_object.write("test")
    f_object.close()
于 2013-09-26T22:23:09.300 回答