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

ここで提示したファイルの抽象化された問題に関する問題を修正するため、ミリムースの回答を以下の正しいものとしてマークしました。残念ながら、私が使用していた 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 is correct that f_object is still holding a reference to the last file in the list. You simply need to reset or delete that variable. I have run into much weirder situations where references were inexplicably being held onto in the past. Below is a method that can be used to test whether all references have been garbage collected or not. Please note, this method of using weakrefs will cause you no end of headaches if you attempt to use it from within 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
于 2013-09-26T23:10:26.573 に答える
0

ファイルを閉じる必要があります

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