在 Windows 上取消 python 中的停滞文件复制

2023-12-10

在 Windows 上,我想使用 Python 通过网络复制一堆文件。有时,网络没有响应,复制会停止。我想检查是否发生这种情况,并在发生这种情况时跳过有问题的文件。通过询问这个相关问题here,我发现了关于复制文件Ex函数,允许使用回调函数,可以中止文件复制。

Python 中的实现如下所示:

import win32file

def Win32_CopyFileEx( ExistingFileName, NewFileName, Canc = False):
    win32file.CopyFileEx(
        ExistingFileName,                             # PyUNICODE           | File to be copied
        NewFileName,                                  # PyUNICODE           | Place to which it will be copied
        Win32_CopyFileEx_ProgressRoutine,             # CopyProgressRoutine | A python function that receives progress updates, can be None
        Data = None,                                  # object              | An arbitrary object to be passed to the callback function
        Cancel = Canc,                                # boolean             | Pass True to cancel a restartable copy that was previously interrupted
        CopyFlags = win32file.COPY_FILE_RESTARTABLE,  # int                 | Combination of COPY_FILE_* flags
        Transaction = None                            # PyHANDLE            | Handle to a transaction as returned by win32transaction::CreateTransaction
        )

从 CopyFileEx 函数的文档中,我可以看到取消正在运行的副本的两种可能性。

pbCancel [输入,可选]如果该标志设置为TRUE在复制操作期间,操作被取消。否则,副本 操作将继续完成。

我不知道如何做到这一点。我尝试再次使用相同的文件句柄调用相同的函数,但将取消标志设置为TRUE,但这会导致错误,因为有问题的文件正在被另一个进程使用。

另一种可能性似乎是回调函数:

lpProgressRoutine [输入,可选]回调函数的地址 类型 LPPROGRESS_ROUTINE 每次调用另一部分 文件已被复制。该参数可以为 NULL。了解更多 有关进度回调函数的信息,请参阅 CopyProgressRoutine 函数。

The 此 ProgressRoutine 的文档声明,当开始复制或完成复制文件的垃圾时调用此回调。回调函数如果返回可以取消复制过程1 or 2(取消、停止)。然而,当垃圾副本停止时,这个回调函数似乎没有被调用。

所以我的问题是:当它停止时,如何在每个文件的基础上取消此副本?


win32file.CopyFileEx不允许通过Cancel除了布尔值或整数值之外的任何值。在 API 中,它是一个LPBOOL指针,允许调用者在另一个线程中同时设置其值。您必须使用 ctypes、Cython 或 C 扩展才能获得这种级别的控制。下面我使用 ctypes 编写了一个示例。

如果取消复制不起作用,因为线程在同步 I/O 上被阻塞,您可以尝试调用CancelIoEx在进度例程中传递的文件句柄上,或者CancelSynchronousIo取消线程的所有同步 I/O。这些 I/O 取消功能是在 Windows Vista 中添加的。它们在 Windows XP 中不可用,以防您仍然支持它。

import ctypes
from ctypes import wintypes

kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

COPY_FILE_FAIL_IF_EXISTS              = 0x0001
COPY_FILE_RESTARTABLE                 = 0x0002
COPY_FILE_OPEN_SOURCE_FOR_WRITE       = 0x0004
COPY_FILE_ALLOW_DECRYPTED_DESTINATION = 0x0008
COPY_FILE_COPY_SYMLINK                = 0x0800
COPY_FILE_NO_BUFFERING                = 0x1000

CALLBACK_CHUNK_FINISHED = 0
CALLBACK_STREAM_SWITCH  = 1
PROGRESS_CONTINUE = 0
PROGRESS_CANCEL   = 1
PROGRESS_STOP     = 2
PROGRESS_QUIET    = 3

ERROR_REQUEST_ABORTED = 0x04D3

if not hasattr(wintypes, 'LPBOOL'):
    wintypes.LPBOOL = ctypes.POINTER(wintypes.BOOL)

def _check_bool(result, func, args):
    if not result:
        raise ctypes.WinError(ctypes.get_last_error())
    return args

LPPROGRESS_ROUTINE = ctypes.WINFUNCTYPE(
    wintypes.DWORD,         # _Retval_
    wintypes.LARGE_INTEGER, # _In_     TotalFileSize
    wintypes.LARGE_INTEGER, # _In_     TotalBytesTransferred
    wintypes.LARGE_INTEGER, # _In_     StreamSize
    wintypes.LARGE_INTEGER, # _In_     StreamBytesTransferred
    wintypes.DWORD,         # _In_     dwStreamNumber
    wintypes.DWORD,         # _In_     dwCallbackReason
    wintypes.HANDLE,        # _In_     hSourceFile
    wintypes.HANDLE,        # _In_     hDestinationFile
    wintypes.LPVOID)        # _In_opt_ lpData

kernel32.CopyFileExW.errcheck = _check_bool
kernel32.CopyFileExW.argtypes = (
    wintypes.LPCWSTR,   # _In_     lpExistingFileName
    wintypes.LPCWSTR,   # _In_     lpNewFileName
    LPPROGRESS_ROUTINE, # _In_opt_ lpProgressRoutine
    wintypes.LPVOID,    # _In_opt_ lpData
    wintypes.LPBOOL,    # _In_opt_ pbCancel
    wintypes.DWORD)     # _In_     dwCopyFlags

@LPPROGRESS_ROUTINE
def debug_progress(tsize, ttrnsfr, stsize, sttrnsfr, stnum, reason,
                  hsrc, hdst, data):
    print('ttrnsfr: %d, stnum: %d, stsize: %d, sttrnsfr: %d, reason: %d' %
          (ttrnsfr, stnum, stsize, sttrnsfr, reason))
    return PROGRESS_CONTINUE

def copy_file(src, dst, cancel=None, flags=0, 
              cbprogress=None, data=None):
    if isinstance(cancel, int):
        cancel = ctypes.byref(wintypes.BOOL(cancel))
    elif cancel is not None:
        cancel = ctypes.byref(cancel)
    if cbprogress is None:
        cbprogress = LPPROGRESS_ROUTINE()
    kernel32.CopyFileExW(src, dst, cbprogress, data, cancel, flags)

Example

if __name__ == '__main__':
    import os
    import tempfile
    import threading

    src_fd, src = tempfile.mkstemp()
    os.write(src_fd, os.urandom(16 * 2 ** 20))
    os.close(src_fd)
    dst = tempfile.mktemp()

    cancel = wintypes.BOOL(False)
    t = threading.Timer(0.001, type(cancel).value.__set__, (cancel, True))
    t.start()
    try:
        copy_file(src, dst, cancel, cbprogress=debug_progress)
    except OSError as e:
        print(e)
        assert e.winerror == ERROR_REQUEST_ABORTED
    finally:
        if os.path.exists(src):
            os.remove(src)
        if os.path.exists(dst):
            os.remove(dst)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Windows 上取消 python 中的停滞文件复制 的相关文章

  • pydev 调试器:严重警告:此版本的 python 似乎编译不正确(内部生成的文件名不是绝对的)[重复]

    这个问题在这里已经有答案了 通过运行 from sklearn datasets import fetch california housing import pandas as pd pd set option precision 4 m
  • Python模块可以访问英语词典,包括单词的定义[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个 python 模块 它可以帮助我从英语词典中获取单词的定义 当然有enchant 这可以帮助我检查该单词是否存在于英语中
  • Python逻辑运算符优先级[重复]

    这个问题在这里已经有答案了 哪个运算符优先4 gt 5 or 3 lt 4 and 9 gt 8 这会被评估为真还是假 我知道该声明3 gt 4 or 2 lt 3 and 9 gt 10 显然应该评估为 false 但我不太确定 pyth
  • 从 ffmpeg 获取实时输出以在进度条中使用(PyQt4,stdout)

    我已经查看了很多问题 但仍然无法完全弄清楚 我正在使用 PyQt 并且希望能够运行ffmpeg i file mp4 file avi并获取流式输出 以便我可以创建进度条 我看过这些问题 ffmpeg可以显示进度条吗 https stack
  • 通过列表理解压平列表列表

    我正在尝试使用 python 中的列表理解来展平列表 我的清单有点像 1 2 3 4 5 6 7 8 只是为了打印这个列表列表中的单个项目 我编写了这个函数 def flat listoflist for item in listoflis
  • 将数据帧行转换为字典

    我有像下面的示例数据这样的数据帧 我正在尝试将数据帧中的一行转换为类似于下面所需输出的字典 但是当我使用 to dict 时 我得到了索引和列值 有谁知道如何将行转换为像所需输出那样的字典 任何提示都非常感激 Sample data pri
  • 从零开始的 numpy 形状意味着什么

    好的 我发现数组的形状中可以包含 0 对于将 0 作为唯一维度的情况 这对我来说是有意义的 它是一个空数组 np zeros 0 但如果你有这样的情况 np zeros 0 100 让我很困惑 为什么这么定义呢 据我所知 这只是表达空数组的
  • 为什么Python的curses中escape键有延迟?

    In the Python curses module I have observed that there is a roughly 1 second delay between pressing the esc key and getc
  • Pandas 数据帧到 numpy 数组 [重复]

    这个问题在这里已经有答案了 我对 Python 很陌生 经验也很少 我已经设法通过复制 粘贴和替换我拥有的数据来使一些代码正常工作 但是我一直在寻找如何从数据框中选择数据 但无法理解这些示例并替换我自己的数据 总体目标 如果有人真的可以帮助
  • 在Python中调整图像大小

    我有一张尺寸为 288 352 的图像 我想将其大小调整为 160 240 我尝试了以下代码 im imread abc png img im resize 160 240 Image ANTIALIAS 但它给出了一个错误TypeErro
  • 从 python 发起 SSH 隧道时出现问题

    目标是在卫星服务器和集中式注册数据库之间建立 n 个 ssh 隧道 我已经在我的服务器之间设置了公钥身份验证 因此它们只需直接登录而无需密码提示 怎么办 我试过帕拉米科 它看起来不错 但仅仅建立一个基本的隧道就变得相当复杂 尽管代码示例将受
  • 如何从Python中的字符串中提取变量名称和值

    我有一根绳子 data var1 id 12345 name John White python中有没有办法将var1提取为python变量 更具体地说 我对字典变量感兴趣 这样我就可以获得变量的值 id和name python 这是由提供
  • 如何设置 Celery 来调用自定义工作器初始化?

    我对 Celery 很陌生 我一直在尝试设置一个具有 2 个独立队列的项目 一个用于计算 另一个用于执行 到目前为止 一切都很好 我的问题是执行队列中的工作人员需要实例化一个具有唯一 object id 的类 每个工作人员一个 id 我想知
  • 在 pytube3 中获取 youtube 视频的标题?

    我正在尝试构建一个应用程序来使用 python 下载 YouTube 视频pytube3 但我无法检索视频的标题 这是我的代码 from pytube import YouTube yt YouTube link print yt titl
  • Python 将日志滚动到变量

    我有一个使用多线程并在服务器后台运行的应用程序 为了无需登录服务器即可监控应用程序 我决定包括Bottle http bottlepy org为了响应一些HTTP端点并报告状态 执行远程关闭等 我还想添加一种查阅日志文件的方法 我可以使用以
  • 无法在 osx-arm64 上安装 Python 3.7

    我正在尝试使用 Conda 创建一个带有 Python 3 7 的新环境 例如 conda create n qnn python 3 7 我收到以下错误 Collecting package metadata current repoda
  • mac osx 10.8 上的初学者 python

    我正在学习编程 并且一直在使用 Ruby 和 ROR 但我觉得我更喜欢 Python 语言来学习编程 虽然我看到了 Ruby 和 Rails 的优点 但我觉得我需要一种更容易学习编程概念的语言 因此是 Python 但是 我似乎找不到适用于
  • 如何在 OSX 上安装 numpy 和 scipy?

    我是 Mac 新手 请耐心等待 我现在使用的是雪豹 10 6 4 我想安装numpy和scipy 所以我从他们的官方网站下载了python2 6 numpy和scipy dmg文件 但是 我在导入 numpy 时遇到问题 Library F
  • 具有自定义值的 Django 管理外键下拉列表

    我有 3 个 Django 模型 class Test models Model pass class Page models Model test models ForeignKey Test class Question model M
  • 列表值的意外更改

    这是我的课 class variable object def init self name name alias parents values table name of the variable self name 这是有问题的函数 f

随机推荐