2011-07-14 115 views
1

以下列方式调用os.rename()后,处理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()吗?

+4

为什么你先打开它然后重命名它? – Jacob

+0

'f = open('foo.txt','rw')'在我的系统上产生了一个'ValueError' - 可能你的意思是'r +'?这真的是你正在运行的代码吗? – multipleinterfaces

+0

这与os.rename无关。你需要模式'r +' –

回答

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

os.rename()在不知道引用此文件的任何打开的文件对象的情况下对纯文件名起作用。因此,在对底层文件进行操作后,您不能依赖文件对象,因此关闭它可能是正确的做法。