windows 10上的os.rename,os.replace和shutil.move错误

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了windows 10上的os.rename,os.replace和shutil.move错误相关的知识,希望对你有一定的参考价值。

我正在尝试使用Windows 10上的重命名实现简单的文件锁定。我有以下测试程序重命名文件以锁定它,然后打开并读取它,并重命名它以解锁它。但是,当我使用不同的参数同时运行其中两个时,我看到间歇性错误(例如test.py 1,test.py 2)

import sys
import os
from time import sleep
import shutil

def lockFile():
    while True:
        try:
            os.replace("testfile", "lockfile"+sys.argv[1])
            if(os.path.exists("lockfile"+sys.argv[1])):
                print("successfully locked", flush=True)
                print(os.stat("lockfile"+sys.argv[1]))
            else:
                print("failed to lock", flush=True)
                raise BaseException()
            return
        except:
            print("sleeping...", flush=True)
            sleep(1)

def unlockFile():
    while True:
        try:
            os.replace("lockfile"+sys.argv[1], "testfile")
            if(os.path.exists("testfile")):
                print("successfully unlocked", flush=True)
            else:
                print("failed to unlock", flush=True)
                raise BaseException()
            return
        except:
            print("sleeping...", flush=True)
            sleep(1)

while True:
    lockFile()
    if(os.path.exists("lockfile"+sys.argv[1])):
        print("file is available", flush=True)
    else:
        print("file is not available", flush=True)
    with open(("lockfile"+sys.argv[1])) as testFile:
        contents = testFile.read()
        print(contents.rstrip(), flush=True)
    unlockFile()

我看到的是偶尔重命名/替换/移动不会抛出异常,os.path.exists说锁定文件存在,我可以统计锁定文件,然后突然锁定文件消失了我无法打开它:

successfully locked
os.stat_result(st_mode=33206, st_ino=9288674231797231, st_dev=38182903, st_nlink=1, st_uid=0, st_gid=0, st_size=12, st_atime=1536956584, st_mtime=1536956584, st_ctime=1536942815)
file is not available
Traceback (most recent call last):
  File "test.py", line 41, in <module>
    with open(("lockfile"+sys.argv[1])) as testFile:
FileNotFoundError: [Errno 2] No such file or directory: 'lockfile2'
答案

我认为部分问题是os.path.exists lies

目录将文件名缓存到文件句柄映射。最常见的问题是:

•您有一个打开的文件,您需要检查该文件是否已被更新的文件替换。在stat()返回新文件的信息而不是打开的文件之前,您必须刷新父目录的文件句柄缓存。

◦实际上这种情况还有另一个问题:旧文件可能已被删除并被新文件替换,但这两个文件可能具有相同的inode。您可以通过刷新打开文件的属性缓存来检查这种情况,然后查看fstat()是否因ESTALE而失败。

•您需要检查文件是否存在。例如一个锁文件。内核可能已缓存该文件不存在,即使实际上它也存在。您必须刷新父目录的负文件句柄缓存以查看该文件是否确实存在。

因此,有时当您的函数检查lockFile()函数中是否存在路径时,它实际上并不存在。

另一答案

好的,基于上面链接的帖子,os.path lies,我拼凑了一个解决方案。这可能仍然只是幸运时间,此时仅适用于Windows。如果我在执行os.path.exists检查之前将subprocess.Popen更改为重命名/替换或省略os.stat,则它不起作用。但是这段代码似乎没有遇到问题。测试了5个同时运行的脚本,没有睡眠调用。

def lockFile():
    while True:
        try:
            p = subprocess.Popen("rename testfile lockfile"+sys.argv[1], shell=True,
                                 stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
            result = p.wait()
            statresult = os.stat("lockfile"+sys.argv[1])
            if(os.path.exists("lockfile"+sys.argv[1])):
                print("successfully locked", flush=True)
                print(os.stat("lockfile"+sys.argv[1]), flush=True)
            else:
                print("failed to lock", flush=True)
                raise BaseException()
            return
        except BaseException as err:
            print("sleeping...", flush=True)
            #sleep(1)

def unlockFile():
    while True:
        try:
            p = subprocess.Popen("rename lockfile"+sys.argv[1] + " testfile", shell=True,
                                 stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
            result = p.wait()
            statresult = os.stat("testfile")
            if(os.path.exists("testfile")):
                pass
            else:
                print("failed to unlock", flush=True)
                raise BaseException()
            return
        except BaseException as err:
            print("sleeping...", flush=True)
            #sleep(1)

以上是关于windows 10上的os.rename,os.replace和shutil.move错误的主要内容,如果未能解决你的问题,请参考以下文章

用 Python 重命名文件似乎不起作用(os.rename)

os.rename 在重命名为带有 utf 字符的内容时添加了一个额外的字符

PermissionError: [Errno 1] for os.rename as quick action

Python3.x基础学习-os模块学习

python -- os处理模块

os模块