以下列方式致电Bad file descriptor
后处理os.rename()
错误的最佳方法是什么?
f = open('foo.txt', 'rw')
os.rename(f.name, f.name + ".bak")
在文件系统中,不再是foo.txt
,而是foo.txt.bak
然而..
f.name
代替foo.txt
foo.txt.bak
但是...
f.write("test")
给出Bad file descriptor
有更好的方法来更新文件描述符吗?
即使文件已被重命名,我是否还应该致电f.close()
?
答案 0 :(得分:4)
您可以编写一个重命名打开文件的函数。基本上,您关闭,重命名和重新打开文件,保留文件位置和模式等属性。重新打开模式的一些调整是必要的 - 如果文件的模式是“w”,以相同的模式重新打开它将丢失其中的所有内容,因此在重新打开时我们使用“r +”模式。 (这不是完美的,因为它允许对文件的读访问,这是以前没有的,但它是我们能做的最好的。)你当然会得到一个全新的file
对象,这是函数的返回值。
import os
def rename_open_file(fileobj, newname):
name = fileobj.name
mode = fileobj.mode.lower()
posn = fileobj.tell()
fileobj.close()
os.rename(name, newname)
newmode = mode
if "w" in mode: # can't reopen with "w" mode since
newmode = "r+" # it would empty the file; use "r+"
if "b" in mode:
newmode += "b"
fileobj = open(name, newmode)
fileobj.seek(posn)
return fileobj
f = rename_open_file(f, f.name + ".bak")
如果您有多个file
对象引用打开的文件,当然这没有用;所有其他参考文献可能会破裂。
警告:文件的name
属性不一定是完整路径,因此如果您使用相对路径打开文件并且在打开文件后更改了目录,则这不起作用。如果这是一个问题,您可以编写自己的open()
,在开放时间(使用os.path.abspath()
)计算文件的完整路径名。
此外,不保留打开文件时给出的缓冲区大小,因为这不会记录在文件对象的任何位置。编写自己的open()
也可以解决这个问题。最简单的方法是继承file
。
from os.path import abspath
class open(file):
def __init__(self, filename, mode="r", buffering=-1):
file.__init__(self, abspath(filename), mode, buffering)
self.buffering = buffering
然后你可以为你的功能增加保持缓冲:
import os
def rename_open_file(fileobj, newname):
name = fileobj.name
mode = fileobj.mode.lower()
posn = fileobj.tell()
buff = fileobj.buffering
fileobj.close()
os.rename(name, newname)
newmode = mode
if "w" in mode: # can't reopen with "w" mode since
newmode = "r+" # it would empty the file; use "r+"
if "b" in mode:
newmode += "b"
fileobj = open(name, newmode, buff)
fileobj.seek(posn)
return fileobj
您还可以为文件对象编写包装器类,而不是为file
创建子类,并让它通过对包装对象的所有file
方法调用。然后rename()
可以是包装器的方法,并执行上述所有操作。由于调用代码将保留对包装器的引用,因此不需要知道底层file
对象是不同的。我将把它留作练习。 : - )
答案 1 :(得分:1)
os.rename()在纯文件名上工作,而不知道任何引用此文件的打开文件对象。因此,在对基础文件执行操作后,您不能依赖文件对象,因此关闭它可能是正确的做法。