Python的高级文件操作(shutil模块)
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
如果让我们用python的文件处理来进行文件拷贝,想必很多小伙伴的思路是:使用打开2个文件对象,源文件读取内容,写入目标文件中来完成拷贝过程。但是这样丢失stat数据信息(权限)等,因为根本没有复制这些信息过去。那目录复制又这咋办呢?
Python提供了一个方便的库shutil(高级文件操作)。它可以解决上面提到的问题,接下来我们来一起学习。
一.复制
1>.copyfilobj
1 #!/usr/bin/env python 2 #_*_conding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie 5 6 import shutil 7 8 src_file = r"E:\temp\a.txt" 9 dest_file = r"E:\temp\a.txt-1" 10 11 #写入测试数据 12 with open(src_file,"w",encoding="utf8") as f: 13 f.write("尹正杰到此一游!") 14 15 with open(src_file,"r",encoding="utf8") as f1: 16 with open(dest_file,"w") as f2: 17 """ 18 文件对象的复制,f1和f2是open函数打开的文件对象,仅复制内容。后面的length指定了表示buffer的大小。这个长度咱们 19 可以不指定,因为该函数有默认值,即"16*1024",建议使用IDE查看源码 20 """ 21 shutil.copyfileobj(f1,f2,length=4096) 22 print("文件拷贝成功") 23 24 25 26 #以上代码输出结果如下: 27 文件拷贝成功
2>.copyfile
1 #!/usr/bin/env python 2 #_*_conding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie 5 6 import shutil 7 8 src_file = r"E:\temp\a.txt" 9 dest_file = r"E:\temp\a.txt-2" 10 11 #写入测试数据 12 with open(src_file,"w",encoding="utf8") as f: 13 f.write("尹正杰到此一游!") 14 15 with open(src_file,"r") as f1: 16 with open(dest_file,"w") as f2: 17 shutil.copyfile(src_file,dest_file) #复制文件内容,不含元数据。本质上调用的就是copyfileobj,所以不带元数据内容复制。 18 print("文件拷贝成功") 19 20 21 22 #以上代码输出结果如下: 23 文件拷贝成功
3>.copymode
1 #!/usr/bin/env python 2 #_*_conding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie 5 6 import shutil,os 7 8 src_file = r"E:\temp\a.txt" 9 dest_file = r"E:\temp\a.txt-1" 10 11 print(os.stat(src_file)) 12 print(os.stat(dest_file)) 13 14 shutil.copymode(src_file,dest_file) #仅仅复制权限,该方法在Linux系统看起来比较直观 15 16 print(os.stat(src_file)) 17 print(os.stat(dest_file))
4>.copystat
1 #!/usr/bin/env python 2 #_*_conding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie 5 6 import shutil,os 7 8 src_file = r"E:\temp\a.txt" 9 dest_file = r"E:\temp\a.txt-1" 10 11 print(os.stat(src_file)) 12 print(os.stat(dest_file)) 13 14 shutil.copystat(src_file,dest_file) #复制元数据,stat包含权限 15 16 print(os.stat(src_file)) 17 print(os.stat(dest_file))
5>.copy
1 #!/usr/bin/env python 2 #_*_conding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie 5 6 import shutil,os 7 8 src_file = r"E:\temp\a.txt" 9 dest_file = r"E:\temp\a.txt-1" 10 11 print(os.stat(src_file)) 12 print(os.stat(dest_file)) 13 14 """ 15 复制文件内容,权限和部分元数据,不包括创建时间和修改时间。本质上调用的是copyfile和copymode方法,可以使用IDE查看源码 16 """ 17 shutil.copy(src_file,dest_file) 18 19 print(os.stat(src_file)) 20 print(os.stat(dest_file))
6>.copy2
1 #!/usr/bin/env python 2 #_*_conding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie 5 6 import shutil,os 7 8 src_file = r"E:\temp\a.txt" 9 dest_file = r"E:\temp\a.txt-3" 10 11 print(os.stat(src_file)) 12 print(os.stat(dest_file)) 13 14 """ 15 copy2比copy多了复制全部元数据,但需要平台支持。本质上调用的是copyfile和copystat函数。 16 """ 17 shutil.copy2(src_file,dest_file) 18 19 print(os.stat(src_file)) 20 print(os.stat(dest_file))
7>.copytree
1 #!/usr/bin/env python 2 #_*_conding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie 5 6 import shutil,os 7 8 src_file = r"E:\temp\test" 9 dest_file = r"E:\temp\bak" 10 11 12 def my_ignore(src,names): 13 ig = filter(lambda x:x.startswith("a"),names) 14 return set(ig) 15 16 """ 17 递归复制目录。默认使用copy2,也就是带更多的元数据复制。 18 函数签名为: 19 def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,ignore_dangling_symlinks=False) 20 其中src,dst必须都是目录,src必须存在,dst必须不存在。 21 ignore = func,提供一个"callable(src, names) -> ignored_names"。提供一个函数,提供一个函数,它会被调用。src是源目录, 22 names是os.listdir(src)的结果,就是列出src中的文件名,返回值要被过滤的文件名的set类型数据。 23 """ 24 shutil.copytree(src_file,dest_file,ignore=my_ignore)
二.删除
1 #!/usr/bin/env python 2 #_*_conding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie 5 6 import shutil 7 8 dest_file = r"E:\temp\bak" 9 10 """ 11 递归删除,如果Linux的"rm -rf"一样危险,慎用哈。 12 它不是原子性操作,有可能删除错误,就会中断,已经删除的就删除啦。 13 其函数签名为: 14 def rmtree(path, ignore_errors=False, onerror=None) 15 其中ignore_errors为True就表示忽略vuow,当为Flase或者omitted时onerror生效。 16 onerror为callable接受函数function,path和execinofie。 17 """ 18 shutil.rmtree(dest_file) #删除的目标目录必须存在哟!否则会抛出异常的~
三.移动
1 #!/usr/bin/env python 2 #_*_conding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:http://www.cnblogs.com/yinzhengjie 5 6 import shutil 7 8 src_file = r"E:\temp\test\a.txt" 9 dest_file = r"E:\temp\test\b.txt" 10 11 12 """ 13 递归移动文件,目录到目标,返回目标。 14 本身使用的时os.rename方法,这个在源码中可以看到。 15 如果不支持rename,如果时目录则copytree再删除源目录。 16 默认使用copy2方法。 17 """ 18 shutil.move(src_file,dest_file)
四.小试牛刀
shutil还有打包功能,生成tar并压缩。支持压缩格式有zip,gz,bz,xz。如果有需要的小伙伴可以自行查阅一下源码的实现方式,我这里就不罗嗦了。
下面有几个可以使用shutil模块的案例,仅供参考。
1>.指定一个源文件,实现copy到目标目录。
例如:
把/tmp/test.txt 拷贝到 /tmp/test.txt-bak
1 #!/usr/bin/env python 2 #_*_coding:utf-8_*_ 3 #@author :yinzhengjie 4 #blog:https://www.cnblogs.com/yinzhengjie 5 #EMAIL:y1053419035@qq.com 6 7 8 from os import path 9 10 basedir = "/tmp/" 11 12 src = "test.txt" 13 14 dst = "test.txt-bak" 15 16 src = path.join(basedir,src) 17 18 dst = path.join(basedir,dst) 19 20 #写入测试内容 21 with open(src,"w",encoding="utf-8") as f: 22 f.writelines("\n".join(("yinzhengjie","jason","https://www.cnblogs.com/yinzhengjie"))) 23 24 #自定函数实现文件复制 25 def copy(src,dst): 26 with open(src,"rb") as f1: 27 with open(dst,"wb") as f2: 28 length = 16 * 1024 29 while True: 30 buffer = f1.read(length) #需要注意的是,这里需要一个缓冲区。 31 if not buffer: 32 break 33 f2.write(buffer) 34 35 #调用咱们自定义的函数 36 copy(src,dst)