Python系列教程(三十四):shutil模块

    到目前为止,不管是前面学的os模块,还是pathlib模块,都没有涉及到文件的复制和移动操作,所以要复制一个文件,只能开打一个文件,然后读取文件内容,再写到另外一个文件,但是这显示是不科学的。
    今天介绍的这个shutil模块,就可以实现文件的复制和移动,还有删除和压缩打包功能。

  一、shutil模块  

1、copyfile(src, dst, follow_symlinks=True) -> None

    说明:复制文件

    ① src是源文件,dst是目标文件

    ② follow_symlinks:指明src如果是链接文件,那最终取的是真实文件,还是链接文件本身,True,表示跟踪链接文件,复制真实文件,Flase,则复制链接文件本身

    ③ 不管目标文件是否存在,都会复制文件

    ④ 仅仅复制文件内容,不复制源文件的元数据

>>> import shutil

#第一次执行:目标文件不存在,复制文件
>>> shutil.copyfile('/etc/fstab','/tmp/fstab2')
'/tmp/fstab2'

#第二次执行:目标文件已存在,覆盖文件
>>> shutil.copyfile('/etc/fstab','/tmp/fstab2')
'/tmp/fstab2'

#复制真实文件
>>> shutil.copyfile('/etc/rc.local','/tmp/rc.local1')
'/tmp/rc.local1'

#复制链接文件
>>> shutil.copyfile('/etc/rc.local','/tmp/rc.local2',follow_symlinks=False)
'/tmp/rc.local2'

[python@jimmy ~]$ ll test1.py 
-rwxr-xr-x 1 python python 1995 Apr  2 16:29 test1.py

#copyfile仅仅复制文件内容,元数据没有复制过去
>>> shutil.copyfile('/home/python/test1.py','/tmp/test2.py')
[root@jimmy tmp]# ll test2.py 
-rw-rw-r-- 1 python python 1995 Apr  2 16:30 test2.py

2、copymode(src, dst, follow_symlinks=True) -> None

    说明:复制文件

    ① src是源文件,dst是目标文件

    ② follow_symlinks:True表示跟踪链接文件,复制真实文件的mode,如果为Flase,则复制链接文件本身的mode

    ③ 仅仅复制文件的mode,不复制文件内容,所以src和dst文件都必须存在

[python@jimmy ~]$ ll test1.py 
-rwxr-xr-x 1 python python 1995 Apr  2 16:29 test1.py

#dst目标文件不存在
>>> shutil.copymode('/home/python/test1.py','/tmp/test3.py')
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/test3.py'

#先手动创建一个空文件
[python@jimmy ~]$ touch /tmp/test3.py

#查看src和dst文件的stat信息
>>> os.stat('/home/python/test1.py')
os.stat_result(st_mode=33261, st_ino=601216, st_dev=64769, st_nlink=1, st_uid=1000, st_gid=1000, st_size=1995, st_atime=1554193742, st_mtime=1554193742, st_ctime=1554193753)

>>> os.stat('/tmp/test3.py')
os.stat_result(st_mode=33204, st_ino=133729, st_dev=64769, st_nlink=1, st_uid=1000, st_gid=1000, st_size=0, st_atime=1554194439, st_mtime=1554194439, st_ctime=1554194439)

#文件的mode复制过来了,但是文件为空,没有复制文件内容
>>> shutil.copymode('/home/python/test1.py','/tmp/test3.py')
>>> os.stat('/tmp/test3.py')
os.stat_result(st_mode=33261, st_ino=133729, st_dev=64769, st_nlink=1, st_uid=1000, st_gid=1000, st_size=0, st_atime=1554194439, st_mtime=1554194439, st_ctime=1554194534)

[root@jimmy tmp]# cat test3.py

3、copystat(src, dst, follow_symlinks=True) -> None

    说明:复制文件

    ① src是源文件,dst是目标文件

    ② follow_symlinks:True表示跟踪链接文件,复制真实文件,如果为Flase,则复制链接文件本身

    ③ 仅仅复制文件的stat元数据,不复制文件内容,所以src和dst文件都必须存在

    ④ stat元数据包括mode,atime和mtime,但是不包括文件的属主属组和ctime,文件的属主属组由执行用户决定

#dst目标文件不存在
>>> shutil.copystat('/home/python/test1.py','/tmp/test3.py')
FileNotFoundError: [Errno 2] No such file or directory

#先手动创建一个空文件
[python@jimmy ~]$ touch /tmp/test3.py

#查看src和dst文件的stat信息
>>> os.stat('/home/python/test1.py')
os.stat_result(st_mode=33261, st_ino=601216, st_dev=64769, st_nlink=1, st_uid=1000, st_gid=1000, st_size=1995, st_atime=1554193742, st_mtime=1554193742, st_ctime=1554193753)

>>> os.stat('/tmp/test3.py')
os.stat_result(st_mode=33188, st_ino=133729, st_dev=64769, st_nlink=1, st_uid=0, st_gid=0, st_size=0, st_atime=1554195059, st_mtime=1554195059, st_ctime=1554195059)

#文件的stat原数据复制过来了,但是文件为空,没有复制文件内容
>>> shutil.copystat('/home/python/test1.py','/tmp/test3.py')
>>> os.stat('/tmp/test3.py')
os.stat_result(st_mode=33261, st_ino=133729, st_dev=64769, st_nlink=1, st_uid=0, st_gid=0, st_size=0, st_atime=1554193742, st_mtime=1554193742, st_ctime=1554195116)

[root@jimmy tmp]# cat test3.py

4、copy(src, dst, follow_symlinks=True) -> None

    说明:复制文件

    ① copy = copyfile + copymode

    ② 复制文件内容 + 文件的mode

    ③ 不管目标文件是否存在,都会复制文件

>>> os.stat('/home/python/test1.py')
posix.stat_result(st_mode=33261, st_ino=601216, st_dev=64769L, st_nlink=1, st_uid=1000, st_gid=1000, st_size=1995, st_atime=1554193742, st_mtime=1554193742, st_ctime=1554193753)

#复制了文件内容和文件mode权限
>>> shutil.copy('/home/python/test1.py','/tmp/test2.py')
>>> os.stat('/tmp/test2.py')
posix.stat_result(st_mode=33261, st_ino=131367, st_dev=64769L, st_nlink=1, st_uid=0, st_gid=0, st_size=1995, st_atime=1554195683, st_mtime=1554195683, st_ctime=1554195683)

5、copy2(src, dst, follow_symlinks=True) -> None

    说明:复制文件

    ① copy2 = copyfile + copystat

    ② 复制文件内容 + 文件的stat元数据(mode、atime、mtime)

    ③ 不管目标文件是否存在,都会复制文件

    ④ copy2不会复制属主属组,文件的属主属组由执行用户决定

>>> os.stat('/home/python/test1.py')
posix.stat_result(st_mode=33261, st_ino=601216, st_dev=64769L, st_nlink=1, st_uid=1000, st_gid=1000, st_size=1995, st_atime=1554193742, st_mtime=1554193742, st_ctime=1554193753)

#复制了文件内容、文件mode权限和文件的atime、mtime
>>> shutil.copy2('/home/python/test1.py','/tmp/test2.py')
>>> os.stat('/tmp/test2.py')
posix.stat_result(st_mode=33261, st_ino=131367, st_dev=64769L, st_nlink=1, st_uid=0, st_gid=0, st_size=1995, st_atime=1554193742, st_mtime=1554193742, st_ctime=1554195885)

6、copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2) -> None

    说明:复制目录

    ① src必须是一个目录,dst必须不存在

    ② ignore:过滤文件,默认不过滤,如果要过滤文件,需要传递一个函数,函数的格式是:func(src,names) ->set,copytree会自动传递参数src和names,src就是目录地址,names是os.listdir(src)的结果,就是src目录中所有文件的一个列表,返回值是一个set类型,里面存放要被过滤的文件名。

    ③ copytree默认使用copy2复制文件

    ④ 类似linux的cp -a命令,但是cp -a会复制属主属组,而copytree不会

[root@jimmy tmp]# tree wordpress/
wordpress
|-- fstab
|-- init.d
|   |-- functions
|   |-- netconsole
|   |-- network
|   |-- rc.local
|   |   `-- shells
|   `-- README
`-- rc.local -> rc.d/rc.local

#dst目录已经存在
>>> shutil.copytree('/tmp/wordpress','/tmp/wordpress2')
OSError: [Errno 17] File exists: '/tmp/wordpress2'

#不过滤文件,默认复制所有文件
>>> shutil.copytree('/tmp/wordpress','/tmp/wordpress2')
[root@jimmy tmp]# tree wordpress
wordpress
|-- fstab
|-- init.d
|   |-- functions
|   |-- netconsole
|   |-- network
|   |-- rc.local
|   |   `-- shells
|   `-- README
`-- rc.local -> rc.d/rc.local

#过滤函数,过滤链接文件
>>> def ignore(src,names):
>>>     result = filter(lambda x:os.path.islink(os.path.join(src,x)),names)
>>>     return set(result)

>>> shutil.copytree('/tmp/wordpress','/tmp/wordpress3',ignore=ignore)

[root@jimmy tmp]# tree wordpress3
wordpress3
|-- fstab
`-- init.d
    |-- functions
    |-- netconsole
    |-- network
    |-- rc.local
    |   `-- shells
    `-- README

7、rmtree(path,ignore_errors=False,onerror=None) -> None

    说明:递归删除目录

    ① 相当于linux的rm -rf命令,删除过程中如果发生中断,不会回滚

    ② ignore_errors:是否忽略错误,默认不忽略

    ③ onerror为callable,接收函数

#删除一个文件,抛出异常
shutil.rmtree('/tmp/fstab2')
NotADirectoryError: [Errno 20] Not a directory: '/tmp/fstab2'

#成功递归删除了一个非空目录
shutil.rmtree('/tmp/wordpress3')

8、move(src,dst,copy_function=copy2) -> 新的路径

    说明:移动文件或者目录到目标目录,返回一个目标

    ① 可以移动文件,目录,多层目录

    ② 默认是调用os.rename或者copy2方法

#移动一个文件到目录中
shutil.move('/tmp/fstab2','/home/python')
'/home/python/fstab2'

shutil.move('/tmp/wordpress','/home/python')
'/home/python/wordpress'

9、make_archive(base_name, format, root_dir=None, base_dir=None,  owner=None, group=None)

    说明:对目录进行打包和压缩

    ① base_name:压缩包的文件名字,并且会自动给压缩文件添加指定的压缩格式后缀,支持相对路径和绝对路径,如果是相对路径,就放在当前工作目录

    ② format:支持的打包压缩格式:"zip", "tar","gztar","bztar",or "xztar"

    ③ root_dir:指定要打包压缩的目录地址,压缩包里的文件的路径是相对路径

    ④ base_dir:指定要打包压缩的目录地址,压缩包里的文件的路径是绝对路径

    ⑤ owner和group:指定压缩包的属主属组

#对文件进行压缩打包,抛出异常
shutil.make_archive('/tmp/test2.py.tar','zip','/tmp/test2.py')
NotADirectoryError: [Errno 20] Not a directory: '/tmp/test2.py'

#使用root_dir指定源文件
shutil.make_archive('/tmp/wordpress','zip',root_dir='/tmp/wordpress')
'/tmp/wordpress.zip'
[root@jimmy tmp]# unzip wordpress.zip 
Archive:  wordpress.zip
   creating: init.d/
  inflating: fstab                   
   creating: init.d/rc.local/
  inflating: init.d/network          
  inflating: init.d/functions        
  inflating: init.d/netconsole       
  inflating: init.d/README           
  inflating: init.d/rc.local/shells

#使用base_dir指定源文件  
shutil.make_archive('/tmp/wordpress2','zip',base_dir='/tmp/wordpress')  
'/tmp/wordpress2.zip'  
[root@jimmy tmp]# unzip wordpress2.zip 
Archive:  wordpress2.zip
   creating: tmp/wordpress/
   creating: tmp/wordpress/init.d/
  inflating: tmp/wordpress/fstab     
   creating: tmp/wordpress/init.d/rc.local/
  inflating: tmp/wordpress/init.d/network  
  inflating: tmp/wordpress/init.d/functions  
  inflating: tmp/wordpress/init.d/netconsole  
  inflating: tmp/wordpress/init.d/README  
  inflating: tmp/wordpress/init.d/rc.local/shells

10、unpack_archive(filename, extract_dir, format=None)

    说明:

    ① filename:解压的文件名

    ② extract_dir:解压的位置

    ③ format:解压格式,如果不指定,会自动判断

shutil.unpack_archive('/tmp/wordpress2.zip','/tmp')

Jimmy's Blog ,版权所有丨如未注明,均为原创丨本网站采用BY-NC-SA协议进行授权,转载请注明转自:https://www.xjimmy.com/python-34-shutil.html

Leave a Comment