高级文件操作模块shutil
常用方法
copy拷贝方法
- copyfileobj(fsrc,fdst[,length]) #拷贝文件对象,将fsrc文件对象内容拷贝到fdst文件对象中。复制文件内容,不含元数据
- fsrc:源文件对象,是open打开的文件对象
- fdst: 目标文件对象,是open打开的文件对象
- length:缓冲区buffer的大小,可选参数,默认是16*1024
- 注意: 如果源文件是文本模式打开,目标文件一定也要是文本模式写入
- python对应原码如下:
def copyfileobj(fsrc, fdst, length=16*1024): """copy data from file-like object fsrc to file-like object fdst""" while 1: buf = fsrc.read(length) if not buf: break fdst.write(buf)
- coypfile(src,dst,*,follow_symlinks=True) #根据文件路径,拷贝文件。复制文件内容,不含元数据。本质上是用copyfileobj对象拷贝
- src:源文件路径,可以是Path对象或者字符串文件路径对象
- dst:目标文件路径,可以是Path对象或者字符串文件路径对象
- follow_symlinks = True,是否跟进链接文件。
- True:表示拷贝链接文件所指向的文件
- False:表示拷贝链接文件本身
- Python中部分源码如下:
def copyfile(src, dst, *, follow_symlinks=True): ##部分代码以省略## if not follow_symlinks and os.path.islink(src): os.symlink(os.readlink(src), dst) else: with open(src, 'rb') as fsrc: with open(dst, 'wb') as fdst: copyfileobj(fsrc, fdst) return dst
- copymode(src,dst,*,follow_symlinks=True) #仅仅复制权限
- src:源文件路径,可以是Path对象或者字符串文件路径对象
- dst:目标文件路径,可以是Path对象或者字符串文件路径对象
- follow_symlinks:是否跟进链接文件。
- True:表示拷贝链接文件所指向的文件
- False:表示拷贝链接文件本身
- copystat(src,dst,*,follow_symlinks=True) #拷贝文件元数据
- src:源文件路径,可以是Path对象或者字符串文件路径对象
- dst:目标文件路径,可以是Path对象或者字符串文件路径对象
- follow_symlinks:是否跟进链接文件。
- True:表示拷贝链接文件所指向的文件
- False:表示拷贝链接文件本身
- copy(src,dst,*,follow_symlinks=True) #复制文件内容和权限已经部分元数据,不包括创建和修改时间。
- 本质上是调用的copyfile,和copymode
- src:源文件
- dst: 目标文件路径
- follow_symlinks: 是否跟进链接文件
- copy2(src,dst,*,follow_symlinks=True) #比copy多了复制全部元数据,但需要平台支撑。
- 本质上调用的是copyfile,copystat
- src:源文件
- dst: 目标文件路径
- follow_symlinks: 是否跟进链接文件
- copytree(src,dst,symlinks=False,ignore=None,copy_function=copy2,ignore_dangling_symlinks=False) #递归拷贝文件
- src:源文件路径,必须是目录,必须存在
- dst: 目标文件路径,必须是目录,可以不是实际存在
- symlinks: 是否拷贝链接文件本身,默认值为False 表示跟进链接文件。
- False 拷贝链接文件所指向的文件
- True 拷贝链接文件本身,不跟进链接文件。
- ignore:是一个函数,提供一个callable(src,names)->ignored_names。用于过滤哪些条件的目录不需要拷贝。默认值为None表示不需要过滤,会默认生成一个空set()集合给ignored_names
- collable(src,names)->ignored_names
- src 源目录
- names 是os.litdir(src)的结果,就是列出src中的文件名
- ignored_names:要被过滤的文件名的set类型数据。
- 原码中对应位置代码如下:
names = os.listdir(src) if ignore is not None: ignored_names = ignore(src, names) else: ignored_names = set() os.makedirs(dst) errors = [] for name in names: if name in ignored_names: continue pass #后面代码这里省略,可以查看python中copytree原码
- collable(src,names)->ignored_names
- copy_function:是一个函数,默认为copy2拷贝函数,拷贝时带上文件元数据信息
- ignore_dangling_symlinks: 链接文件所指向的文件不存在,是否出现异常,默认值为False
- False: 表示,如果有异常,正常出现
- True: 屏蔽链接文件所指向的文件不存在出现的异常
- 综合简单示例:
import shutil,os from pathlib import Path h = Path("a/b/c/d") h.mkdir(parents=True,exist_ok=True) #创建目录 h.parent.joinpath("e/").mkdir(parents=True,exist_ok=True) h.parent.joinpath("f/").mkdir(parents=True,exist_ok=True) names = ["a.txt","b.txt","c.txt","c2.txt","c3.txt","d.txt","b1.txt","b2.txt","a1.txt","a2.txt"] for i in names: #创建文件 f = os.open(h.joinpath(i),os.O_CREAT) os.close(f) f = os.open(h.parent.joinpath(i),os.O_CREAT) os.close(f) f = os.open(h.parent.joinpath("e/",i),os.O_CREAT) os.close(f) f = os.open(h.parent.joinpath("f/",i),os.O_CREAT) os.close(f) #过滤以a开头和以c开头的文件。 fun = lambda src,name: {*filter(lambda name: name.startswith("a") or name.startswith("c"),names)} #将a目录中的所有内容拷贝到b目录中 shutil.copytree(Path("a"),Path("b"),ignore=fun)
rm删除方法
- shutil.rmtree(path,ignore_errors=False,οnerrοr=None) #递归删除,如同rm -rf一样危险,慎用。肯能会出现删除错误而中断,已经删除的就删除了。
- path:要删除的路径对象
- ignore_errors:是否忽略删除错误。默认为False表示不忽略。
- True 忽略删除错误
- False 不忽略删除错误,如果出现错误就终止,不过错误之前删除的文件已经删除。
- onerror:是个函数,与ignore_errors结合使用。调用方式为:onerror(os.lstat, path, sys.exc_info())
- 原码部分代码如下
if ignore_errors: def onerror(*args): pass elif onerror is None: def onerror(*args): raise # 部分代码省略
move移动方法
- move(src,dst,copy_function=copy2) #移动文件或目录到目标,返回目标。
- 本身使用的是os.rename方法。如果不支持rename方法,如果是目录就会使用copytree在删除源目录。默认使用copy2方法
- src :源目录,或文件
- dst :目标
- copy_function :复制时的拷贝函数,默认为copy2
- python源码如下:
def move(src, dst, copy_function=copy2): real_dst = dst if os.path.isdir(dst): if _samefile(src, dst): # We might be on a case insensitive filesystem, # perform the rename anyway. os.rename(src, dst) return real_dst = os.path.join(dst, _basename(src)) if os.path.exists(real_dst): raise Error("Destination path '%s' already exists" % real_dst) try: os.rename(src, real_dst) except OSError: if os.path.islink(src): linkto = os.readlink(src) os.symlink(linkto, real_dst) os.unlink(src) elif os.path.isdir(src): if _destinsrc(src, dst): raise Error("Cannot move a directory '%s' into itself" " '%s'." % (src, dst)) copytree(src, real_dst, copy_function=copy_function, symlinks=True) rmtree(src) else: copy_function(src, real_dst) os.unlink(src) return real_dst