11

我在 Windows 2012 服务器上使用 Python 看门狗模块来监视共享驱动器上出现的新文件。当看门狗注意到新文件时,它会启动数据库恢复过程。

但是,看门狗似乎会在创建文件的第二秒尝试恢复文件,而不是等到文件完成复制到共享驱动器。所以我将事件更改为 on_modified 但有两个 on_modified 事件,一个是文件最初被复制时,另一个是文件复制完成时。

如何处理两个 on_modified 事件以仅在复制到共享驱动器的文件完成时触发?

当多个文件同时复制到共享云端硬盘时会发生什么?

这是我的代码

import time
import subprocess
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

class NewFile(FileSystemEventHandler):
    def process(self, event):
        if event.is_directory:
            return

    if event.event_type == 'modified':            
        if getext(event.src_path) == 'gz':
            load_pgdump(event.src_path)

    def on_modified(self, event):
        self.process(event)

def getext(filename):
    "Get the file extension"
    file_ext = filename.split(".",1)[1]
    return file_ext

def load_pgdump(src_path):    
    restore = 'pg_restore command ' + src_path
    subprocess.call(restore, shell=True)

def main():
    event_handler = NewFile()
    observer = Observer()
    observer.schedule(event_handler, path='Y:\\', recursive=True)
    observer.start()

    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()

if __name__ == '__main__':
    main()
4

9 回答 9

10

在您的 on_modified 事件中,只需通过观察文件大小等到文件完成复制。

提供更简单的循环:

historicalSize = -1
while (historicalSize != os.path.getsize(filename)):
  historicalSize = os.path.getsize(filename)
  time.sleep(1)
print "file copy has now finished"
于 2016-12-12T16:29:33.743 回答
3

我正在使用以下代码等待文件复制(仅适用于 Windows):

from ctypes import windll
import time

def is_file_copy_finished(file_path):
    finished = False

    GENERIC_WRITE         = 1 << 30
    FILE_SHARE_READ       = 0x00000001
    OPEN_EXISTING         = 3
    FILE_ATTRIBUTE_NORMAL = 0x80

    if isinstance(file_path, str):
        file_path_unicode = file_path.decode('utf-8')
    else:
        file_path_unicode = file_path

    h_file = windll.Kernel32.CreateFileW(file_path_unicode, GENERIC_WRITE, FILE_SHARE_READ, None, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, None)

    if h_file != -1:
        windll.Kernel32.CloseHandle(h_file)
        finished = True

    print 'is_file_copy_finished: ' + str(finished)
    return finished

def wait_for_file_copy_finish(file_path):
    while not is_file_copy_finished(file_path):
        time.sleep(0.2)

wait_for_file_copy_finish(r'C:\testfile.txt')

这个想法是尝试使用共享读取模式打开一个文件进行写入。如果其他人正在写入它,它将失败。

享受 ;)

于 2017-10-09T10:49:05.467 回答
3

我会添加评论,因为这不是您问题的答案,而是一种不同的方法……但我还没有足够的代表。您可以尝试监视文件大小,如果它停止更改,您可以假设复制已完成:

copying = True
size2 = -1
while copying:
    size = os.path.getsize('name of file being copied')
    if size == size2:
        break
    else:
        size2 = os.path.getsize('name of file being copied')
        time.sleep(2)
于 2015-08-19T11:01:56.070 回答
1

这对我有用。在 windows 中也用 python3.7 测试过

while True:
        size_now = os.path.getsize(event.src_path)
        if size_now == size_past:
            log.debug("file has copied completely now size: %s", size_now)
            break
            # TODO: why sleep is not working here ?
        else:
            size_past = os.path.getsize(event.src_path)
            log.debug("file copying size: %s", size_past)
于 2019-03-29T10:29:40.457 回答
1

在 linux 上,您还会收到close事件。解决方案是等待处理文件,直到文件关闭。我的方法是添加on_closed处理。

class Handler(FileSystemEventHandler):
    def __init__(self):
        self.files_to_process = set()

    def dispatch(self, event):
        _method_map = {
            'created': self.on_created,
            'closed': self.on_closed
        }

    def on_created(self, event):
        self.files_to_process.add(event.src_path)

    def on_closed(self, event):
        self.files_to_process.remove(event.src_path)
        actual_processing(event.src_path)
于 2021-09-01T12:03:17.427 回答
1

老我知道,但我最近想出了一个解决这个确切问题的方法。就我而言,我只关心 wav 和 mp3 文件。此函数将确保仅将完全复制的文件发送到 makerCore(),因为创建的占位符文件没有任何扩展名,并且始终以“未准备好”结束。文件完成后,它将再次触发看门狗模块,但这次带有扩展名。这也将同时处理多个文件。

def on_created(event):
    #print(event)
    if str(event.src_path).endswith('.mp3') or str(event.src_path).endswith('.wav'):
        makerCore(event)
    else:
        print('not ready')
于 2021-06-07T12:40:29.803 回答
1

我最近与看门狗有类似的问题。一个相当简单但不是很聪明的解决方法是让我使用两个元素列表检查文件大小的变化,一个用于“过去”,一个用于“现在”。一旦值相等,复制就完成了。

编辑:像这样的东西。

past = 0
now = 1
value = [past, now]
while True:
    # change

    # test
    if value[0] == value[1]:
        break
    else:
        value = [value[1], value[0]]
于 2015-08-19T11:03:25.497 回答
0

我正在使用一种不同的方法,它可能不是最优雅的方法,但如果您可以控制复制文件,那么在任何平台上都很容易做到。

只是在复制完成之前对文件的名称进行了“进行中”,然后重命名文件。然后,您可以有一个 while 循环等待名称没有“进行中”的文件存在,并且您很好。

于 2018-06-18T12:20:41.150 回答
0

我已经尝试过检查文件大小 - 等待 - 再次检查上面许多人建议的例程,但它不是很可靠。为了让它更好地工作,我添加了一个检查文件是否仍然被锁定。

    file_done = False
    file_size = -1

    while file_size != os.path.getsize(file_path):
        file_size = os.path.getsize(file_path)
        time.sleep(1)

    while not file_done:
        try:
            os.rename(file_path, file_path)
            file_done = True
        except:
            return True
于 2020-02-20T22:11:54.947 回答