如何使用 tqdm 监控文件批量读写与处理进度

如何使用 tqdm 监控文件批量读写与处理进度

本教程详细介绍了如何利用 Python tqdm 库有效监控文件操作进度,特别是在批量处理(如加密/解密)场景下。我们将探讨如何计算总进度并为每个文件操作提供更新回调,从而实现对整个文件处理过程的直观进度条显示,提升用户体验。

引言:理解文件操作进度监控的挑战

python 中进行文件操作时,尤其是涉及大量文件或大文件时,提供一个进度条可以显著提升用户体验。tqdm 是一个功能强大的库,能够轻松为循环或迭代器添加进度条。然而,许多 tqdm 的示例都集中在网络下载场景,例如使用 requests 库的 iter_content 方法,它能以分块的方式迭代数据流,从而方便地更新进度条。

对于本地文件操作,特别是像 file.write(data) 这样一次性写入大量数据的场景,直接跟踪 write() 内部的进度会变得复杂,因为 write() 通常是一个原子操作,它会尝试一次性将所有数据写入。这意味着我们无法在单次 write() 调用过程中获得细粒度的进度更新。

本教程的目标是解决一个更常见但同样重要的场景:如何在使用 file.read() 读取整个文件并进行处理(如编码/加密),然后使用 file.write() 写回时,监控 整个文件处理过程批量文件处理过程 的总进度。我们将通过计算所有文件的总大小来初始化进度条,并在每个文件处理完成后更新进度。

tqdm 库基础回顾

tqdm 库的核心思想是为可迭代对象提供一个进度条。它的基本用法非常简单:

from tqdm import tqdmimport timefor i in tqdm(range(100)):    time.sleep(0.01) # 模拟耗时操作

对于更复杂的场景,我们需要手动控制进度条:

tqdm(total=…): 初始化一个进度条,并指定总工作量。pbar.update(n): 将进度条向前推进 n 个单位。pbar.close(): 关闭进度条。

在文件操作中,通常我们将文件大小作为进度单位,total 就是所有文件的总字节数,而 update(n) 则是在处理完一个大小为 n 的文件后调用。

实现批量文件处理进度监控

为了实现对批量文件处理的进度监控,我们需要两个关键步骤:首先,计算出所有待处理文件的总大小,作为 tqdm 进度条的 total 值;其次,设计一个机制,在每个文件处理完成后,能够通知进度条进行更新。

我们将通过两个辅助函数来实现这一目标:

1. 计算总文件大小:iter_files 函数

这个函数负责遍历指定文件夹及其子文件夹中的所有文件,并生成每个文件的路径和大小。这是为了在初始化 tqdm 进度条之前,能够计算出所有文件的总字节数。

import osfrom tqdm import tqdmdef iter_files(folder):    """    遍历指定文件夹及其子文件夹中的所有文件,并生成文件的路径和大小。    """    for root, _, files in os.walk(folder):        for file in files:            file_path = os.path.join(root, file)            try:                # 确保文件存在且可访问,避免PermissionError                file_size = os.path.getsize(file_path)                yield file_size, file_path            except OSError:                print(f"警告: 无法获取文件大小或访问文件: {file_path}")                continue

iter_files 函数是一个生成器,它不会一次性将所有文件信息加载到内存中,这对于处理大量文件非常高效。

2. 构建带进度的迭代器:iter_with_progress 函数

这个函数是核心部分,它接收一个文件夹路径,并返回一个迭代器。这个迭代器在每次迭代时,会提供一个 done 回调函数、当前文件的大小和文件路径。done 回调函数的作用是,在当前文件处理完成后,通知 tqdm 进度条更新相应的字节数。

def iter_with_progress(folder):    """    为指定文件夹中的文件处理创建一个带进度的迭代器。    初始化一个tqdm进度条,并为每个文件提供一个更新进度的回调函数。    """    # 计算所有文件的总大小,作为tqdm的total参数    total_size = sum(s for s, _ in iter_files(folder))    # 初始化tqdm进度条    # unit='B' 表示单位是字节    # unit_scale=True 自动缩放单位(B, KB, MB, GB)    # unit_divisor=1024 使用1024作为单位除数    progress_bar = tqdm(unit='B',                        total=total_size,                        unit_scale=True,                        unit_divisor=1024,                        desc="总进度")    # 遍历文件,并为每个文件提供一个更新进度的回调    for size, file_path in iter_files(folder):        # 定义一个闭包函数,用于在文件处理完成后更新进度条        # 每次调用done(),进度条就会增加当前文件的大小        done_callback = lambda: progress_bar.update(size)        yield done_callback, size, file_path    # 确保进度条在所有文件处理完成后关闭    progress_bar.close()

iter_with_progress 函数首先调用 iter_files 来计算 total_size,然后创建一个全局的 tqdm 进度条。在每次迭代时,它返回一个 done_callback,当这个回调被调用时,它会告诉 progress_bar 增加当前文件的大小。

3. 整合到文件处理逻辑

现在,我们可以将上述函数整合到您的文件加密/解密逻辑中。假设您的加密/解密操作发生在循环内部,并且每次处理一个文件。

import osfrom base64 import b85encode, b85decode # 导入base85编码/解码函数import time # 模拟耗时操作# 假设的输入目录input_dir = 'C:Python311test_files' # 请替换为您的实际目录# 确保测试目录存在并创建一些示例文件if not os.path.exists(input_dir):    os.makedirs(input_dir)    with open(os.path.join(input_dir, 'file1.txt'), 'w') as f:        f.write("This is a test file for encryption and decryption. " * 100)    with open(os.path.join(input_dir, 'file2.bin'), 'wb') as f:        f.write(os.urandom(50000)) # 50KB random data    print(f"Created sample files in {input_dir}")print(f"开始处理目录: {input_dir}")# 使用 iter_with_progress 迭代文件,并获取进度更新回调for done_callback, file_size, file_path in iter_with_progress(input_dir):    file_name = os.path.basename(file_path)    print(f"正在处理: {file_name} ({file_size} 字节)...", end='')    try:        # 模拟文件读取、编码/加密、写入过程        with open(file_path, 'rb') as encrypting_file:            original_bytes = encrypting_file.read()            # 模拟加密操作:这里使用b85encode作为示例            # 注意:b85encode会增加数据大小,但tqdm是基于原始文件大小更新的            # 如果需要精确跟踪加密后写入的字节数,需要调整total和update逻辑            encoded_bytes = b85encode(original_bytes)         with open(file_path, 'wb') as output_file:            output_file.write(encoded_bytes)        print(f"完成处理: {file_name}                               ") # 清除行尾的进度信息        # 调用 done_callback 通知进度条更新当前文件大小        done_callback()     except PermissionError:        print(f"跳过 (权限不足): {file_name}                      ")        # 对于跳过的文件,如果不想计入总进度,则不调用done_callback        # 如果跳过也算作处理完成,则可以调用 done_callback()        done_callback() # 也可以选择不调用,这样进度条会显示未完成    except Exception as e:        print(f"处理 {file_name} 时发生错误: {e}                   ")        done_callback() # 即使出错也更新进度,表示该文件已尝试处理print("所有文件处理完毕。")

在这个整合示例中,iter_with_progress(input_dir) 提供了遍历所有文件的能力,并且在每次循环迭代时,我们获得了 done_callback。在每个文件的加密(或任何处理)完成后,我们调用 done_callback(),这将通知 tqdm 进度条增加相应的文件大小,从而实现对整个批处理过程的进度监控。

注意事项与优化

内存消耗与大文件处理:您原始代码中的 b85encode(encryptingfile.read()) 会将整个文件内容读入内存。对于非常大的文件(例如几GB),这可能会导致内存溢出。优化建议: 对于大文件,应采用分块读写的方式。这意味着您需要以固定大小的块读取文件,对每个块进行处理,然后将处理后的块写入新文件。在这种情况下,tqdm.update() 的参数应该是每次写入的块大小,而不是整个文件的大小。例如:

# 伪代码:分块读写chunk_size = 4096with open(file_path, 'rb') as infile, open(output_path, 'wb') as outfile:    # pbar for single file, total = file_size    with tqdm(total=file_size, unit='B', unit_scale=True, desc=file_name) as pbar_file:        while True:            chunk = infile.read(chunk_size)            if not chunk:                break            processed_chunk = b85encode(chunk) # 假设处理            outfile.write(processed_chunk)            pbar_file.update(len(chunk)) # 更新当前文件的进度# 外部的 done_callback() 仍然可以在这里调用,表示整个文件处理完成

这种分块处理方式将提供更细粒度的单个文件内部进度。

file.write() 的原子性:再次强调,本教程的方案是监控 文件完成总字节数处理 的进度,而不是单次 file.write() 操作内部的进度。如果您希望监控单个 write() 操作的内部进度,那意味着您需要手动将要写入的数据分成小块,然后循环写入并更新进度条,但这通常只在处理非常大的单一数据流时才有意义。

错误处理:在实际应用中,务必加入健壮的错误处理机制。例如,当文件不存在、权限不足或在读写过程中发生其他I/O错误时,能够优雅地处理并记录问题。示例代码中已加入了 PermissionError 的处理。

tqdm 参数的灵活运用:tqdm 提供了丰富的参数来自定义进度条的显示。例如:

desc: 进度条前缀描述。ncols: 进度条的宽度。bar_format: 自定义进度条的显示格式。leave: 控制进度条在完成后是否保留在终端。根据您的需求调整这些参数,可以使进度条更加符合您的应用场景。

总结

通过本教程,我们学习了如何利用 tqdm 库有效地监控 Python 中批量文件处理的进度。核心思想是计算所有待处理文件的总大小作为 tqdm 的 total 值,并为每个文件处理提供一个回调函数来更新进度。这种方法尤其适用于文件加密、解密、压缩、转换等需要遍历文件夹并处理每个文件的场景,极大地提升了脚本的用户友好性。同时,我们也讨论了处理大文件时的内存优化策略,即采用分块读写,以及理解 file.write() 操作的原子性对进度条实现的影响。掌握这些技术,将使您的文件处理脚本更加专业和高效。

以上就是如何使用 tqdm 监控文件批量读写与处理进度的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1363387.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月14日 03:23:32
下一篇 2025年12月14日 03:23:44

相关推荐

  • 使用tqdm跟踪文件写入与处理进度

    本文详细介绍了如何利用Python的tqdm库有效地跟踪文件处理(如加密、解密或批量写入)的进度。文章通过自定义迭代器函数,实现了在文件级别而非字节级别对操作总进度进行可视化,解决了传统tqdm示例主要针对下载流式数据的局限性,并提供了清晰的代码示例和集成指导,帮助开发者为文件操作添加直观的进度条。…

    2025年12月14日
    000
  • 使用tqdm高效跟踪文件写入与目录处理进度

    本文深入探讨了如何利用Python的tqdm库来跟踪文件写入操作的进度,尤其是在处理大型文件或批量处理目录下文件时。我们将介绍两种核心策略:针对单个大文件写入的块级进度跟踪,以及针对整个目录文件处理的宏观进度显示。通过详细的代码示例和解释,读者将学会如何将tqdm集成到文件加密、解密或其他数据转换流…

    2025年12月14日
    000
  • Python tqdm 实践:构建文件处理与写入操作的进度条

    本文深入探讨了如何利用 Python tqdm 库为文件处理和写入操作添加进度条。不同于常见的下载进度追踪,我们将展示一种策略,通过监控文件级别的处理完成情况来更新进度条,特别适用于一次性读取和写入整个文件内容的场景。文章将提供详细的代码示例和实现步骤,帮助开发者在文件加密、转换等任务中实现直观的进…

    2025年12月14日
    000
  • 使用tqdm追踪文件写入进度

    本文详细介绍了如何利用Python的tqdm库来可视化文件操作的进度,特别是针对批量文件处理场景。我们将探讨tqdm在追踪文件写入或处理完成情况时的应用,而非单一写入操作的字节级进度。通过自定义迭代器函数,我们可以有效地聚合文件夹内所有文件的总大小,并以专业、清晰的方式展示处理进度,从而提升用户体验…

    2025年12月14日
    000
  • 解决NumPy中uint8整数溢出导致对数函数返回-inf的问题

    在Python图像处理中,当对uint8类型的NumPy数组应用如log(x + 1)这样的对数函数时,若像素值为255,可能会意外得到-inf结果。这是因为uint8类型在执行255 + 1时会发生整数溢出,导致结果回绕为0,而log(0)则为负无穷。本教程将详细解释这一现象,并提供将数组显式转换…

    2025年12月14日
    000
  • NumPy图像处理:对数变换中的数据类型溢出陷阱与规避

    在NumPy中对图像数据进行对数变换时,若原始图像为uint8类型,np.log(x + 1)运算可能因整数溢出导致x + 1变为0,进而产生-inf结果。这是因为uint8类型255加1会回绕至0。解决方案是在进行对数运算前,将图像数据类型转换为浮点数(如np.float32),以避免溢出,确保计…

    2025年12月14日
    000
  • 解决NumPy中uint8整数溢出导致对数函数返回负无穷的问题

    在Python中使用NumPy库进行图像处理时,开发者经常会遇到各种数据类型相关的挑战。其中一个常见但容易被忽视的问题是,当对uint8类型的图像数据执行某些数学运算(如对数变换)时,可能会出现意料之外的负无穷(-inf)结果。这通常是由于NumPy数组的特定数据类型(uint8)在执行加法运算时发…

    2025年12月14日
    000
  • Google 地图评论数据抓取:提升稳定性和准确性

    本文旨在解决使用自动化工具抓取 Google 地图评论数据时遇到的不完整或不准确问题,特别是评论平均分和评论数量的抓取遗漏。我们将分析常见原因,并重点介绍如何利用 Selenium 结合动态定位策略和显式等待机制,构建更健壮、更可靠的爬虫,确保数据抓取的完整性和准确性。 1. 问题背景与常见挑战 在…

    2025年12月14日
    000
  • 实现分层计算的递归函数

    本文介绍如何使用递归函数来处理分层依赖关系的计算,特别是当计算公式依赖于其他指标时。通过构建指标缩写与ID的字典,并结合 pandas.eval 函数,可以有效地解析和计算复杂的公式,最终得到所需的结果。 在处理具有层级依赖关系的计算问题时,递归函数是一种强大的工具。例如,当一个指标的计算公式依赖于…

    2025年12月14日
    000
  • 使用 CP437 编码打印删除线文本

    本文介绍了如何在支持 CP437 编码的打印机上打印删除线文本。通过使用特定的控制字符 b”xST”,可以在打印机上实现删除线效果,替代了传统方案中无效的字符叠加方法,提供了一种简洁高效的解决方案。 在某些打印场景下,我们需要在打印文本中添加删除线效果。如果打印机使用的是 C…

    2025年12月14日
    000
  • CP437 编码打印机实现删除线文本打印指南

    本文详细阐述了如何在采用 CP437 编码的打印机上实现删除线文本效果。针对常见的 UTF-8 打印机解决方案(如 b”x1bx4c”)和通用控制字符(如 b”x08″)在 CP437 环境下无效的问题,本教程提供了一个专用的字节序列 b”…

    2025年12月14日
    000
  • 如何在CP437编码的打印机上打印删除线文本

    在CP437编码的打印机上打印删除线文本,通常需要使用特定的控制字符。先前尝试的x1bx4c方法,虽然在UTF-8打印机上有效,但在CP437编码下并不适用。同样,退格键x08也无法实现所需的删除线效果。 解决方案:使用xST命令 在CP437编码的打印机上,可以使用xST命令来实现删除线效果。 x…

    2025年12月14日
    000
  • Python多线程环境下上下文管理器内函数调用的监控与管理

    本文深入探讨了在Python中如何监控特定上下文管理器内函数调用的执行情况,并着重解决了多线程环境下全局状态导致的监控混乱问题。通过引入threading.local实现线程局部存储,以及合理使用线程锁,我们构建了一个健壮的解决方案,确保每个线程的监控上下文独立且互不干扰,同时允许子线程的监控数据汇…

    2025年12月14日
    000
  • Python上下文管理器中函数调用的线程安全监控

    本文探讨了如何在Python中利用上下文管理器监控指定函数的执行,记录函数名和执行时间,并确保在嵌套上下文和多线程环境下的数据隔离与准确性。针对全局变量在多线程中引发的上下文交叉监控问题,文章提出了一种基于threading.local和线程锁的解决方案,实现了主线程与子线程各自上下文的独立管理,并…

    2025年12月14日
    000
  • Python多线程环境中上下文内函数调用监控的线程安全实现

    本文探讨了在Python中如何实现上下文内函数调用的监控,并着重解决了多线程环境下的线程安全问题。通过引入threading.local和线程锁,我们设计了一个分离主线程与子线程处理器的方案,确保每个线程的监控上下文独立且数据准确,同时允许主线程的上下文收集所有线程的监控记录,从而实现高效且可靠的函…

    2025年12月14日
    000
  • 在Python多线程上下文中监控函数调用

    在Python多线程环境下,如何实现上下文感知的函数调用监控。针对原始方案中全局状态导致的多线程安全问题,文章详细阐述了利用threading.local实现线程局部存储,以及通过threading.Lock确保共享资源访问的线程安全机制。通过重构监控处理器,确保每个线程拥有独立的上下文列表,同时允…

    2025年12月14日
    000
  • 解决用户安装Python工具的PATH环境变量问题:以Pipenv为例

    当用户通过pip安装Python工具如Pipenv时,常会遇到PATH环境变量未包含其可执行文件路径的警告。本文将详细指导如何通过修改shell配置文件(如~/.bashrc或~/.profile)将用户安装的二进制文件目录添加到系统PATH中,确保工具能够被正确识别和执行。此外,也将提及使用系统包…

    2025年12月14日
    000
  • Python上下文中的函数调用监控与多线程兼容性实现

    本文深入探讨了在Python中监控特定函数调用、记录其执行时间等信息,并将其关联到特定上下文的需求。针对单线程环境中可行但在多线程场景下因全局状态导致的上下文混淆问题,文章详细介绍了如何利用threading.local和线程锁机制,构建一个线程安全的监控处理器,确保每个线程拥有独立的上下文管理,同…

    2025年12月14日
    000
  • 将用户级Python工具目录添加到Linux PATH环境变量的教程

    当用户通过pip install –user安装Python工具(如Pipenv)时,其可执行文件通常位于用户主目录下的.local/bin中,而该路径默认不在系统环境变量PATH中,导致命令无法直接执行。本教程将详细指导如何通过修改shell配置文件(如~/.profile或~/.ba…

    2025年12月14日
    000
  • 解决Linux系统下用户安装程序(如Pipenv)不在PATH环境变量的问题

    本文详细介绍了在Linux系统上,当通过pip install –user等方式将程序(例如Pipenv)安装到用户目录后,如何解决其可执行文件不在系统PATH环境变量中的问题。教程提供了两种主要方法:通过修改~/.bashrc或~/.profile文件来永久添加自定义路径,以及通过系统…

    2025年12月14日
    000

发表回复

登录后才能评论
关注微信