简体   繁体   English

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

[英]os.rename, os.replace and shutil.move errors on windows 10

I'm trying to implement simple file locking using renaming on windows 10. I've got the following test program that renames a file to lock it, then opens and reads it, and renames it to unlock it. 我试图在Windows 10上使用重命名来实现简单的文件锁定。我有以下测试程序,该程序重命名文件以将其锁定,然后打开并读取它,然后重命名以对其进行解锁。 However, I'm seeing intermittent errors when I run two of these simultaneously using different arguments (eg test.py 1, test.py 2) 但是,当我使用不同的参数同时运行其中两个时,出现间歇性错误(例如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()

What I'm seeing is that occasionally the rename/replace/move doesn't throw an exception, os.path.exists says the locked file is present, I can stat the locked file, and then suddenly the locked file is gone and I can't open it: 我看到的是,偶尔重命名/替换/移动不会引发异常,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'

I think part of the problem is that os.path.exists lies 我认为部分问题是os.path.exists说谎

Directories cache file names to file handles mapping. 目录将文件名缓存到文件句柄映射。 The most common problems with this are: 最常见的问题是:

•You have an opened file, and you need to check if the file has been replaced by a newer file. •您有一个打开的文件,需要检查该文件是否已被较新的文件替换。 You have to flush the parent directory's file handle cache before stat() returns the new file's information and not the opened file's. 您必须先刷新父目录的文件句柄缓存,然后stat()返回新文件的信息,而不返回打开文件的信息。

◦Actually this case has another problem: The old file may have been deleted and replaced by a new file, but both of the files may have the same inode. ◦实际上,这种情况还存在另一个问题:旧文件可能已被删除并被新文件替换,但是两个文件可能具有相同的inode。 You can check this case by flushing the open file's attribute cache and then seeing if fstat() fails with ESTALE. 您可以通过刷新打开文件的属性高速缓存,然后查看fstat()是否因ESTALE失败而检查这种情况。

•You need to check if a file exists. •您需要检查文件是否存在。 For example a lock file. 例如一个锁定文件。 Kernel may have cached that the file does not exist, even if in reality it does. 内核可能已缓存该文件不存在,即使实际上确实存在。 You have to flush the parent directory's negative file handle cache to to see if the file really exists. 您必须刷新父目录的负文件句柄缓存,以查看该文件是否确实存在。

So sometimes when your function is checking to see if the path exists in the lockFile() function, it doesn't actually exist. 因此,有时当您的函数正在检查lockFile()函数中是否存在该路径时,实际上并不存在该路径。

Ok, based on the post linked above, os.path lies , I cobbled together a solution. 好的,根据上面链接的帖子, os.path位于 ,我拼凑了一个解决方案。 This may still just be lucky timing and is only for Windows at this point. 这可能仍然只是幸运的时机,目前仅适用于Windows。 If I change the subprocess.Popen to rename/replace or omit the os.stat before doing the os.path.exists check then it doesn't work. 如果我在执行os.path.exists检查之前将subprocess.Popen更改为重命名/替换或省略os.stat,则它不起作用。 But this code doesn't seem to hit the problem. 但是这段代码似乎没有解决问题。 Tested with 5 simultaneous scripts running and without sleep calls. 使用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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM