我折腾出了一个python脚本——移动文件......

文章讲述了作者如何编写并遇到问题的Python脚本,用于按内容移动文件。脚本利用difflib库进行相似性匹配,但存在缺陷如精确度不高、异常处理不足等。作者分享了学习过程中的经验和对Python简洁易用性的感慨。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、为啥我折腾好几天整个这么个没啥用的脚本?

  1. 如题,我整了个移动文件的python脚本,就…很无语🙄🙄。

  2. 我编程的习惯还不错,写文件还算能分目录写,但我脑子抽了,寻思着优化一下文件结构,然后喜滋滋的整了个python脚本,当时也没多想,一是寻思着胡乱写的脚本应该跑不起来,二是好奇Python脚本是怎么移动文件的。当时竟然没备份文件,结果是Python脚本居然跑起来了,但明显逻辑有问题——我根目录下的文件全跑到一个文件夹里去了。

  3. 但我这情况确实特殊,当时学cmd命令行,用dir \b \s得到的文件夹的文件路径我居然脑抽风保存过,虽然是半个月前的,但总比没有好。

  4. 但我寻思着我也不能一个文件一个文件移动啊,干脆折腾出了一个Python脚本移动文件,我寻思着这个脚本一辈子也就这一次了。



二、这个Python脚本长啥样?

如下模样:

import os
import shutil
import difflib

def get_most_similar_filename(filename, target_filenames):
    return difflib.get_close_matches(filename, target_filenames, n=1, cutoff=0.7)

def move_files(original_dir, target_dir):
    original_filenames = os.listdir(original_dir)
    target_filenames = os.listdir(target_dir)
    not_moved_count = 0

    if not os.path.exists(target_dir):
        os.makedirs(target_dir)

    for filename in original_filenames:
        source_file = os.path.join(original_dir, filename)
        if os.path.isfile(source_file):
            similar_filename = get_most_similar_filename(filename, target_filenames)
            if similar_filename:
                target_file = os.path.join(target_dir, similar_filename[0])
                try:
                    shutil.move(source_file, target_file)
                    print(f"Moved: {filename} -> {similar_filename[0]}")
                except Exception as e:
                    print(f"Error moving {filename} to {target_file}: {e}")
                    not_moved_count += 1
            else:
                print(f"Warning: Target path not found for filename: {filename}")
                not_moved_count += 1
        else:
            print(f"Warning: Source path not found for filename: {filename}")
            not_moved_count += 1

    return not_moved_count

def main():
    original_dir = "D:\\A_Shun_Exclusive\\life_ofuniversity\\code_collection\\copy_vscode_copy\\VSCODE\\"
    target_dir = "D:\\A_Shun_Exclusive\\life_ofuniversity\\code_collection\\C\\VSCODE\\"

    print("Moving files...")
    not_moved_count = move_files(original_dir, target_dir)
    print(f"Total files not moved: {not_moved_count}")

if __name__ == "__main__":
    main()



三、这个脚本怎么用?

  1. 将脚本中的 original_dir 设置为源文件夹的路径,将 target_dir 设置为目标文件夹的路径。
original_dir = "D:\\A_Shun_Exclusive\\life_ofuniversity\\code_collection\\copy_vscode_copy\\VSCODE\\"
target_dir = "D:\\A_Shun_Exclusive\\life_ofuniversity\\code_collection\\C\\VSCODE\\"
  1. 你需要在此脚本文件的同级目录下新建两个文件并存放目录
    请添加图片描述
    注意: 两个文件的命名必须是original_paths.txt(存放原始路径)和target_paths.txt(目标路径)

original_paths.txt
target_paths.txt

  1. 然后运行python文件即可


四、基于此Python脚本作以下简单讲述

这个Python脚本旨在解决一个实际问题:如何将一个文件夹中的文件按照它们的内容移动到另一个文件夹中,并确保它们与目标文件夹中的现有文件有足够的相似性以进行匹配。

以下是脚本的简要讲述:

  1. 获取文件名列表

    • 从源文件夹 (original_dir) 中获取所有文件名。
    • 从目标文件夹 (target_dir) 中获取所有文件名。
  2. 文件移动核心逻辑

    • 对于源文件夹中的每个文件:
      • 首先,检查文件是否存在于源文件夹中,如果不存在,输出警告信息。
      • 然后,使用 difflib.get_close_matches 函数找到在目标文件夹中最相似的文件名。
      • 如果找到了相似的文件名,将源文件移动到目标文件夹中相应的位置,同时输出移动的文件名和目标文件名。
      • 如果没有找到相似的文件名,输出警告信息。
  3. 定制相似性阈值

    • 你可以根据需要调整相似性的阈值,通过修改 get_most_similar_filename 函数中的 cutoff 参数。默认值是 0.7,你可以根据实际情况将其调整为更高或更低的值,以控制匹配的严格程度。
  4. 运行脚本

    • 在脚本中设置源文件夹 (original_dir) 和目标文件夹 (target_dir) 的路径。
    • 运行脚本,它将自动执行文件的移动操作。
  5. 输出信息

    • 脚本会输出每个文件的移动结果,包括已移动的文件名和目标文件名。
    • 如果某些文件无法移动,会输出错误信息和警告信息,同时统计未移动的文件数量。


五、我是如何使用Python脚本语言实现文件移动功能的?

import os
import shutil
import difflib
  • 这里我们导入了三个Python库:os 用于处理文件和目录操作,shutil 用于文件操作(如移动文件),difflib 用于字符串比较(用于找到相似的文件名)。
def get_most_similar_filename(filename, target_filenames):
    return difflib.get_close_matches(filename, target_filenames, n=1, cutoff=0.7)
  • get_most_similar_filename 是一个自定义函数,它的目的是找到与给定文件名(filename)最相似的目标文件名。target_filenames 参数是目标文件名的列表。
  • 我们使用了 difflib.get_close_matches 函数,它接受四个参数:
    • filename:要比较的字符串。
    • target_filenames:目标字符串列表。
    • n:要返回的最佳匹配数量(在此处为1)。
    • cutoff:相似性的阈值,0.7 表示只返回相似度大于等于0.7的匹配项。
def move_files(original_dir, target_dir):
    original_filenames = os.listdir(original_dir)
    target_filenames = os.listdir(target_dir)
    not_moved_count = 0
  • move_files 是另一个自定义函数,它接受两个参数:original_dir(源文件夹路径)和 target_dir(目标文件夹路径)。
  • 使用 os.listdir 函数从源文件夹和目标文件夹中获取文件名列表,并将它们存储在 original_filenamestarget_filenames 中。
  • not_moved_count 是一个计数器,用于跟踪未移动的文件数量。
    if not os.path.exists(target_dir):
        os.makedirs(target_dir)
  • 这个条件检查目标文件夹是否存在。如果不存在,它将使用 os.makedirs 创建目标文件夹。
    for filename in original_filenames:
        source_file = os.path.join(original_dir, filename)
        if os.path.isfile(source_file):
  • 这是一个循环,它遍历 original_filenames 中的每个文件名。
  • 使用 os.path.join 函数创建源文件的完整路径,并将其存储在 source_file 变量中。
  • 使用 os.path.isfile 函数检查 source_file 是否是一个文件,而不是目录。
similar_filename = get_most_similar_filename(filename, target_filenames)
  • 这一行代码的目的是使用 get_most_similar_filename 函数找到与源文件名 (filename) 最相似的目标文件名。
  • get_most_similar_filename 函数被调用,它接受两个参数:源文件名 (filename) 和目标文件名列表 (target_filenames)。
  • 函数返回的结果存储在 similar_filename 变量中,这是一个列表,包含了与源文件名最相似的一个或多个目标文件名。
if similar_filename:
  • 这是一个条件语句,用于检查是否找到了与源文件名相似的目标文件名。如果 similar_filename 列表非空(意味着找到了相似的文件名),则执行以下代码块。
    target_file = os.path.join(target_dir, similar_filename[0])
  • 这一行代码的目的是创建目标文件的完整路径,以便后续将源文件移动到目标位置。
  • 使用 os.path.join 函数将 target_dirsimilar_filename[0](最相似的目标文件名)连接起来,生成目标文件的路径,并将其存储在 target_file 变量中。
    try:
        shutil.move(source_file, target_file)
        print(f"Moved: {filename} -> {similar_filename[0]}")
  • 这里使用了 tryexcept 块,用于尝试执行文件移动操作。
  • shutil.move 函数用于将源文件 (source_file) 移动到目标文件 (target_file) 的位置。
  • 如果移动操作成功,那么会执行 print 语句,输出一条消息,显示已移动的文件名以及目标文件名。
    except Exception as e:
        print(f"Error moving {filename} to {target_file}: {e}")
        not_moved_count += 1
  • 如果在移动文件时发生了任何错误,将进入 except 块。
  • except 块中,我们捕获了异常,并将其存储在 e 变量中。异常是一种表示错误的特殊情况。
  • 然后,我们使用 print 语句输出一条错误消息,其中包含了文件移动失败的详细信息,包括文件名和目标文件名。
  • 同时,我们增加 not_moved_count 计数器的值,以跟踪未能移动的文件数量。
            else:
                print(f"Warning: Target path not found for filename: {filename}")
                not_moved_count += 1
        else:
            print(f"Warning: Source path not found for filename: {filename}")
            not_moved_count += 1
  • 如果找不到相似的文件名,我们会输出警告消息,指出目标文件路径或源文件路径未找到,并增加 not_moved_count 的计数器。
    return not_moved_count
  • 最后,move_files 函数返回未移动的文件数量,以便在主程序中显示。
def main():
    original_dir = "D:\\A_Shun_Exclusive\\life_ofuniversity\\code_collection\\copy_vscode_copy\\VSCODE\\"
    target_dir = "D:\\A_Shun_Exclusive\\life_ofuniversity\\code_collection\\C\\VSCODE\\"
  • main 函数是脚本的主要入口点。
  • 在函数内部,定义了两个变量 original_dirtarget_dir,它们分别存储了源文件夹路径和目标文件夹路径。这些路径是硬编码在脚本中的,通常在实际应用中,用户可以通过命令行参数或配置文件来指定这些路径,以增加灵活性。
    print("Moving files...")
  • 这一行代码用于在控制台输出一条信息,指示脚本正在移动文件。
    not_moved_count = move_files(original_dir, target_dir)
  • 这一行代码调用了之前定义的 move_files 函数,将 original_dirtarget_dir 作为参数传递给该函数。
  • 调用 move_files 函数会执行文件移动操作,并返回未移动的文件数量,这个数量将存储在 not_moved_count 变量中。
    print(f"Total files not moved: {not_moved_count}")
  • 最后,这一行代码输出了未移动的文件数量,以供用户查看。
  • 使用 f-string(格式化字符串),将 not_moved_count 的值插入到输出消息中。
if __name__ == "__main__":
    main()
  • 这是一个条件语句,检查脚本是否直接运行,而不是被其他脚本导入。
  • 如果脚本直接运行(即 __name__ 变量的值为 "__main__"),则调用 main 函数,开始执行文件移动操作。


六、这个脚本还有哪些缺陷?

  1. 相似性匹配不够精确:脚本使用了 difflib.get_close_matches 来寻找最相似的文件名,但它仅基于字符串相似度来匹配文件,可能会出现误匹配的情况,特别是在文件名之间存在较大差异时。对于更高精度的匹配,可以考虑使用更复杂的算法,如文本相似性度量。

  2. 异常处理不够健壮:脚本在文件移动时使用了 tryexcept 块来处理异常,但它捕获了所有异常,包括可能的操作系统或文件系统错误。更好的做法是针对特定类型的异常进行处理,以便更好地了解出现的问题,并采取相应的措施。

  3. 没有回滚机制:如果在文件移动期间发生错误,脚本不会执行回滚操作,而是继续移动下一个文件。这可能导致一些文件被移动,而其他文件未能成功移动。在实际应用中,添加回滚机制,将确保文件操作的原子性。

  4. 不提供用户友好的界面:脚本的配置和使用需要直接编辑脚本文件,对于非技术用户可能不够友好。

  5. 没有错误日志记录:虽然脚本会输出错误消息,但它没有记录这些错误,因此用户无法轻松地回顾或分析错误历史。添加错误日志记录功能可以帮助用户更好地管理问题。

  6. 不处理文件冲突:如果目标文件夹中已经存在与源文件夹中的文件相同的文件名,脚本将直接覆盖目标文件。在一些情况下,可能需要添加处理文件冲突的逻辑,以避免数据丢失。

  7. 缺乏单元测试和文档:脚本缺乏单元测试和详细文档,这使得难以验证其功能是否正常工作,并且难以为其他人提供使用说明。添加适当的测试用例和文档可以提高脚本的可维护性和可用性。

简单聊聊Python

不可否认的是,Python应用的确广泛。任一领域的研究一旦涉及编程,Python都是不错的选择;青少年大多都会接触Python而非其他语言。
为什么?
因为Python足够简单!

  1. Python之禅:Python有一篇著名的文档叫做《Python之禅》(The Zen of Python),其中包含了Python的设计原则和哲学。这篇文档以诗意的方式表达了Python的简洁、可读性和优雅之美。例如,其中的一句是:“优美胜于丑陋”(Beautiful is better than ugly)。

  2. 简单明了的语法:Python足够简洁和直观。它强调可读性,使得代码看起来就像阅读英文一样,非常容易理解。

  3. 交互式解释器:Python的交互式解释器允许你逐行执行代码。

结束语

折腾出这个Python脚本的过程异常痛苦,我常常陷入改错、百度、懵逼的循环中。所以当我实现了我想要的功能时,难以言喻的兴奋感简直让我沉浸其中难以自拔。几乎可以说,我很少有过如此失态的经历。
Python的简洁、优雅让我大吃一惊,我自认使用不管是C语言还是Java语言实现移动文件的功能或许都是一个不小的工程量,我甚至觉得无从下手。
不管前景如何,Python足够有趣,仅此一点,我推荐你们去了解Python。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤酒_21L

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值