Python 在os.rename()之后更新文件描述符

Python 在os.rename()之后更新文件描述符,python,Python,以以下方式调用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.close?os.rename仅用于文件名,而不知道任何引用此文件的打开文

以以下方式调用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.close?

os.rename仅用于文件名,而不知道任何引用此文件的打开文件对象。因此,在对基础文件执行操作后,不能依赖文件对象工作,因此关闭它可能是正确的做法。

os.rename在纯文件名上工作,而不知道任何引用此文件的打开文件对象。因此,在对基础文件执行操作后,不能依赖文件对象工作,因此关闭它可能是正确的做法。

您可以编写一个函数来重命名打开的文件。基本上,您可以关闭、重命名和重新打开文件,并保留文件位置和模式等属性。重新打开时需要对模式进行一些调整-如果文件的模式为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")
如果有多个文件对象引用打开的文件,这当然没有帮助;所有其他引用可能会中断

警告:文件的name属性不一定是完整路径,因此,如果使用相对路径打开文件,并且在打开文件后更改了目录,那么这将不起作用。如果出现问题,可以使用os.path.abspath编写自己的open,在打开时计算文件的完整路径名

此外,打开文件时给定的缓冲区大小不会保留,因为它不会记录在文件对象的任何位置。编写自己的open也可以解决这个问题。最简单的方法是对文件进行子类化

然后,您可以将维护缓冲添加到您的函数中:

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

您还可以为文件对象编写包装类,而不是子类化文件,并让它通过对包装对象的所有文件方法调用。然后重命名可以是包装器的一种方法,并执行上述所有操作。因为调用代码将保留对包装器的引用,所以它不需要知道底层文件对象是不同的。我将把这个作为练习-

您可以编写一个函数来重命名打开的文件。基本上,您可以关闭、重命名和重新打开文件,并保留文件位置和模式等属性。重新打开时需要对模式进行一些调整-如果文件的模式为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")
如果有多个文件对象引用打开的文件,这当然没有帮助;所有其他引用可能会中断

警告:文件的name属性不一定是完整路径,因此,如果使用相对路径打开文件,并且在打开文件后更改了目录,那么这将不起作用。如果出现问题,可以使用os.path.abspath编写自己的open,在打开时计算文件的完整路径名

此外,打开文件时给定的缓冲区大小不会保留,因为它不会记录在文件对象的任何位置。编写自己的open也可以解决这个问题。最简单的方法是对文件进行子类化

然后,您可以将维护缓冲添加到您的函数中:

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

您还可以为文件对象编写包装类,而不是子类化文件,并让它通过对包装对象的所有文件方法调用。然后重命名可以是包装器的一种方法,并执行上述所有操作。因为调用代码将保留对包装器的引用,所以它不需要知道底层文件对象是不同的。我将把这个作为练习-

为什么要先打开它,然后重命名它?f=open'foo.txt',rw'在我的系统上引发了一个ValueError-也许你的意思是'r+'?这真的是您正在运行的代码吗?这与os.rename无关。您需要创建模式“r+”@multipleinterfacesfoo.txt,然后才能执行“rw”@pseudosudo的读取部分,然后读取它,确定是否需要重命名它,关闭它并重命名它。为什么要先打开它,然后重命名它?f=open'foo.txt',rw'在我的系统上引发一个值错误-也许您的意思是“r+”?这真的是密码吗
你正在运行?这与os.rename无关。您需要创建模式“r+”@multipleinterfacesfoo.txt,然后才能执行“rw”@pseudosudo的读取部分,然后读取它,确定是否需要重命名它,关闭它并重命名它。