文章背景: 工作中,经常需要拷贝数据,比如将仪器数据拷贝到指定路径。Python中的shutil模块可以用于文件和文件夹的复制。此外,也可以借助win32file模块来复制文件。
1 复制文件
1.1 shutil模块
1.1.1 shutil.copy
(src, dst, *, follow_symlinks=True)
1.1.2 shutil.copy2
(src, dst, *, follow_symlinks=True)
1.2 pypiwin32模块
1.3 代码示例
2 复制文件夹
2.1 shutil.copytree
2.2 遍历法(自定义函数)
2.3 代码示例
shutil
模块提供了一系列对文件和文件集合的高阶操作。特别是提供了一些支持文件拷贝和删除的函数。
shutil.copy
(src, dst, *, follow_symlinks=True) (1) 将文件 src 拷贝到文件或目录 dst。src 和 dst 应为 路径类对象 或字符串。如果 dst 指定了一个目录,文件将使用 src 中的基准文件名拷贝到 dst 中。如果 dst 指定了一个已存在的文件,它将被替换。返回新创建文件所对应的路径。
(2) copy()
会拷贝文件数据和文件的权限模式。其他元数据,例如文件的创建和修改时间不会被保留。要保留所有原有的元数据,请改用 copy2()
。
shutil.copy2
(src, dst, *, follow_symlinks=True) 类似于 copy()
,区别在于 copy2()
还会尝试保留文件的元数据。
相比于shutil
模块,使用win32file.CopyFile
可以加速文件的复制速度。
要使用win32file.CopyFile
,需要提前安装pypiwin32模块(pip install pypiwin32
)。
win32file.CopyFile(from, to, bFailIfExists)
import time
import win32file
import shutil
source = r"C:\Local\test\123.xlsm"
destination1 = r"C:\Local\test\456.xlsm"
destination2 = r"C:\Local\test\789.xlsm"
time_start = time.time()
win32file.CopyFile(source, destination1, 1)
time_end = time.time()
print("win32耗时:{:.3f}秒".format(time_end - time_start))
time_start = time.time()
shutil.copy2(source, destination2)
time_end = time.time()
print("shutil耗时:{:.3f}秒".format(time_end - time_start))
运行结果:
win32耗时:0.002秒
shutil耗时:0.003秒
shutil.copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, ignore_dangling_symlinks=False, dirs_exist_ok=False)
递归地拷贝以 src 为根路径的整个目录树,返回目标目录。名为 dst 的目标目录不必已存在;它本身和还不存在的父目录都将被自动创建。
遍历待拷贝的目标文件夹,如果是文件夹,则创建空文件夹;如果是文件,则借助win32file.CopyFile
复制文件。代码实现见2.3节。
import os
import time
import win32file
import shutil
def copy_dir(source, destination):
path_list = os.listdir(source) # 获取路径下的文件或路径
for index, item in enumerate(path_list): # 遍历整个路径下的文件和路径,判断是路径还是文件
path_temp = os.path.join(source, path_list[index]) # 得到相对路径或绝对路径
if os.path.isdir(path_temp): # 判断是否为路径(若是,复制目录)
nest_path = os.path.join(destination, path_list[index]) # 为新路径下创建同名路径
os.mkdir(nest_path) # 创建路径
copy_dir(path_temp, nest_path) # 递归遍历
else: # 判断是否为文件(若是,复制文件)
file_path = os.path.join(destination, path_list[index]) # 得到新路径之下的文件名
win32file.CopyFile(path_temp, file_path, 1) # 文件已存在时,1为不覆盖,0为覆盖
source1 = r"C:\Local\test"
destination1 = r"C:\Local\test1"
destination2 = r"C:\Local\test2"
time_start = time.time()
os.mkdir(destination1)
copy_dir(source1, destination1)
time_end = time.time()
print("遍历法耗时:{:.3f}秒".format(time_end - time_start))
time_start = time.time()
shutil.copytree(source1, destination2)
time_end = time.time()
print("shutil耗时:{:.3f}秒".format(time_end - time_start))
遍历法耗时:0.012秒
shutil耗时:0.021秒
注:本文提供两种方法复制文件夹,至于哪种方法耗时更短,因具体工作场景和文件个数而异。
参考资料:
[1] shutil (https://docs.python.org/zh-cn/3.7/library/shutil.html#module-shutil)
[2] Linux 符号链接 (https://chinese.freecodecamp.org/news/linux-symbolic-link/)
[3] Python | shutil.copy() method (https://www.geeksforgeeks.org/python-shutil-copy-method/)
[4] win32file (https://yiyibooks.cn/__src__/meikunyuan6/pywin32/pywin32/PyWin32/win32file.html)
[5] python ImportError: No module named win32file (https://stackoverflow.com/questions/55551188/python-importerror-no-module-named-win32file)
[6] Windows下用Python你会几种copy文件的方法以及效率分析(https://www.jianshu.com/p/7d170088ec62)
[7] python复制文件夹及文件(python复制文件夹及文件 - PythonTechWorld](https://pythontechworld.com/article/detail/cSEi8esxXayx)
[8] Python enumerate() 函数(https://www.runoob.com/python/python-func-enumerate.html)