这是一个练习,学习了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密集型的操作进行了资源限制,在保证效率的同时,也不会因为创建过多的线程影响其他操作的效率。完成顺序同样是无序的。
总结:通过以上三个方法对拷贝文件功能的实现,显而易见的体现出了三种结构的特点。