python学习之多任务实现文件拷贝

版权声明:浅弋、璃鱼的原创 https://blog.csdn.net/qq_35709559/article/details/82350009

这是一个练习,学习了python中的多任务的线程和进程,来个综合性的练习,分别使用单进程单线程、单进程多线程、多进程分别来实现同时拷贝一个文件夹中的多个文件,为了体现出大文件的情况,再每次数据读写的时候加了0.02秒的延时。

基本思路就是拿到源文件夹路径(src_path)和目标路径(dst_dir)。对源文件路径进行拆分,拆分成路径拿到要复制的源文件夹名(file_name)。判断目标路径下是否存在源文件夹,如果存在,就删除。接下来在目标路径下创建文件夹(file_name)。然后获取到原文件夹中的文件列表(src_file_list),便利文件列表中的每个文件,之后的实现就不太一样了:

单进程单线程:在循环中,直接进行复制操作,复制完一个文件之后再进行下一个文件的复制。

单进程多线程:在循环中创建子线程,将复制操作(copy_file)交由子线程完成,而主线程主要负责创建子线程。

多进程:在循环在创建一个进程池全局变量(pool),进入循环中,使用进程池异步操作创建子进程,将复制操作(copy_file)交由子进程,主线程只负责往进程池中添加进程即可。当然还需要在主进程中设置关闭进程池(pool.close()),既所有文件的复制任务创建完成后,主进程不再向进程池中添加进程。设置主进程等待(pool.join()),主进程等待进程操作完成后再退出。

 

单进程单线程,也就是普通方法实现:

代码:

#!/usr/bin/env python
# coding=utf-8

import os
import shutil


if __name__ == '__main__':

    # 获取原文件路径和目标路径
    src_path = ".\\test"
    dst_dir = "F:\\123\\12"

    # 拆分源路径和目标文件夹
    src_dir = src_path.rsplit(os.sep, 1)
    file_name = src_dir[1]

    # 拼接目标文件夹,判断目标路径是否存在;存在-->删除
    dst_file_path = dst_dir + os.sep + file_name
    if os.path.exists(dst_file_path):
        shutil.rmtree(dst_file_path)

    # 创建目标文件夹
    os.mkdir(dst_file_path)
    # 获取原文件夹的文件列表
    src_file_list = os.listdir(src_path)
    # 遍历文件进行复制操作
    for file in src_file_list:
        dst_file_name = dst_file_path + os.sep + file
        src_file_name = src_path + os.sep + file
        with open(dst_file_name, 'wb') as dst_file:
            with open(src_file_name, 'rb') as src_file:
                while True:
                    file_data = src_file.read(1024)
                    if file_data:
                        dst_file.write(file_data)
                    else:
                        print(src_file_name, "-->", dst_file_name, "复制成功...")
                        break

运行结果:

打印文件列表: ['1.txt', '2.txt', '3.txt', '4.txt', '5.txt']
.\test\1.txt --> F:\123\12\test\1.txt 复制成功...
.\test\2.txt --> F:\123\12\test\2.txt 复制成功...
.\test\3.txt --> F:\123\12\test\3.txt 复制成功...
.\test\4.txt --> F:\123\12\test\4.txt 复制成功...
.\test\5.txt --> F:\123\12\test\5.txt 复制成功...

评价:这个方法直接在main中实现没有功能做任何的封装。同时在运行结果中看出,文件操作顺序是按文件列表中的遍历顺序,执行顺序显而易见了。

单进程多线程:在主进程中创建多个线程

代码:

#!/usr/bin/env python
# coding=utf-8

import os
import shutil
import threading
import time


# 将功能封装进函数中
def copy_file(src_path, dst_file_path, file):
    dst_file_name = dst_file_path + os.sep + file
    src_file_name = src_path + os.sep + file
    with open(dst_file_name, 'wb') as dst_file:
        with open(src_file_name, 'rb') as src_file:
            while True:
                file_data = src_file.read(1024)
                if file_data:
                    dst_file.write(file_data)
                    time.sleep(0.02)
                else:
                    print(src_file_name, "-->", dst_file_name, "复制成功...")
                    break


if __name__ == '__main__':

    # 获取原文件路径和目标路径
    src_path = ".\\test"
    dst_dir = "F:\\123\\12"

    # 拆分源路径和目标文件夹
    src_dir = src_path.rsplit(os.sep, 1)
    file_name = src_dir[1]

    # 拼接目标文件夹,判断目标路径是否存在;存在-->删除
    dst_file_path = dst_dir + os.sep + file_name
    if os.path.exists(dst_file_path):
        shutil.rmtree(dst_file_path)

    # 创建目标文件夹
    os.mkdir(dst_file_path)
    # 获取原文件夹的文件列表
    src_file_list = os.listdir(src_path)
    print("打印文件列表:", src_file_list)
    # 遍历文件进行复制操作
    for file in src_file_list:
        # 创建线程
        copy_thread = threading.Thread(target=copy_file, args=(src_path, dst_file_path, file))
        copy_thread.start()

运行结果:

打印文件列表: ['1.txt', '2.txt', '3.txt', '4.txt', '5.txt']
.\test\1.txt --> F:\123\12\test\1.txt 复制成功...
.\test\4.txt --> F:\123\12\test\4.txt 复制成功...
.\test\2.txt --> F:\123\12\test\2.txt 复制成功...
.\test\3.txt --> F:\123\12\test\3.txt 复制成功...
.\test\5.txt --> F:\123\12\test\5.txt 复制成功...

评价:多线程实现,将复制操作进行了封装(copy_file),也就是说将可以用多任务实现的功能进行了封装,以便利创建线程。同时,文件复制成功的顺序和文件列表的顺序显然是不一样的。

多线程:

代码:

#!/usr/bin/env python
# coding=utf-8

import os
import shutil
import multiprocessing as mult
import time


# 将功能封装进函数中
def copy_file(src_path, dst_file_path, file):
    
    """功能代码同上"""
    pass  


if __name__ == '__main__':

    # 获取原文件路径和目标路径
    src_path = ".\\test"
    dst_dir = "F:\\123\\12"

    # 拆分源路径和目标文件夹
    src_dir = src_path.rsplit(os.sep, 1)
    file_name = src_dir[1]

    # 拼接目标文件夹,判断目标路径是否存在;存在-->删除
    dst_file_path = dst_dir + os.sep + file_name
    if os.path.exists(dst_file_path):
        shutil.rmtree(dst_file_path)

    # 创建目标文件夹
    os.mkdir(dst_file_path)
    # 获取原文件夹的文件列表
    src_file_list = os.listdir(src_path)
    print("打印文件列表:", src_file_list)

    # 创建进程池
    pool = mult.Pool(3)

    # 遍历文件进行复制操作
    for file in src_file_list:
        # 创建进程
        pool.apply_async(copy_file, args=(src_path, dst_file_path, file))

    # 关闭进程池
    pool.close()
    # 主进程等待进程池
    pool.join()

运行结果:

打印文件列表: ['1.txt', '2.txt', '3.txt', '4.txt', '5.txt']
.\test\1.txt --> F:\123\12\test\1.txt 复制成功...
.\test\4.txt --> F:\123\12\test\4.txt 复制成功...
.\test\2.txt --> F:\123\12\test\2.txt 复制成功...
.\test\3.txt --> F:\123\12\test\3.txt 复制成功...
.\test\5.txt --> F:\123\12\test\5.txt 复制成功...

评价:多进程程实现,同样的将复制操作进行了封装(copy_file),使用进程池,对类似的IO密集型的操作进行了资源限制,在保证效率的同时,也不会因为创建过多的线程影响其他操作的效率。完成顺序同样是无序的。

总结:通过以上三个方法对拷贝文件功能的实现,显而易见的体现出了三种结构的特点。

猜你喜欢

转载自blog.csdn.net/qq_35709559/article/details/82350009
今日推荐