Python入门之shutil模块

shutil模块提供了大量的文件的高级操作。特别针对文件拷贝和删除,主要功能为目录和文件操作以及压缩操作。对单个文件的操作也可参见os模块。

  注意即便是更高级别的文件复制函数(shutil.copy(),shutil.copy2())也不能复制所有文件的元数据。这意味着在POSIX平台上,文件的所有者和组以及访问控制列表都将丢失。在Mac OS中资源fork和其他元数据无法使用。这意味着资源将丢失,文件类型和创建者代码将不正确。在Windows上,文件所有者,ACL和备用数据流不会被复制。

  功能:高级文件操作。类型:标准模块相关模块: os 标准模块。zipfile 标准模块。tarfile 标准模块。

1、shutil.copyfileobj(fsrc, fdst[, length]):复制文件内容(不包含元数据)从类文件对象src到类文件对dst。可选参数length指定缓冲区的大小,负数表示一次性读入。默认会把数据切分成小块拷贝,以免占用太多内存。注意:拷贝是从fsrc的当前文件开始;若如果dst存在,则会被覆盖

#!/usr/bin/env python3

import shutil
import os

print(os.system("cat /tmp/shutil_new.txt"))  #打印出未复制内容前的文件

print("*"*60)
shutil.copyfileobj(open("/tmp/shutil_old.txt","r"),open("/tmp/shutil_new.txt","w"),10)

print(os.system("cat /tmp/shutil_new.txt"))  #打印被复制后的文件
执行结果:
[root@localhost 20170712]# ./shutil_cpobj.py 
0
************************************************************
\S
Kernel \r on an \m

0

2、shutil.copyfile(src,dst):将src复制为dst;dst必须是完整的目标文件并且具有可写权限,否则将抛出异常;如果src和dst是同一个文件,将抛出shutil.Error;如果dst已存在,将会被覆盖;特殊文件,如字符或块设备、管道不能使用此功能,因为copyfile会打开并阅读文件,src和dst是字符串形式的路径。

  2.1 正常复制

#!/usr/bin/env python3

import shutil
import os

os.system("ls /tmp/shutil_file")      #查看目录/tmp/shutil_file内容

shutil.copyfile("/tmp/shutil_file/shutil_old.txt","/tmp/shutil_file/shutil_new.txt")    #将文件shutil_old.txt复制shutil_new.txt
print("*"*60)
os.system("cat /tmp/shutil_file/shutil_new.txt")    #打印被复制的文件内容
执行结果:
[root@localhost 20170717]# cat /tmp/shutil_file/shutil_old.txt     #查看源文件内容
Welcome to the Linux world
Now we start learning python
[root@localhost 20170717]# ./shutil_cpfile.py 
shutil_old.txt
************************************************************
Welcome to the Linux world
Now we start learning python

  2.2 目标文件存在复制

#!/usr/bin/env python3

import shutil
import os

os.system("cat /tmp/shutil_file/shutil_exist.txt")      #查看存在的文件内容

shutil.copyfile("/tmp/shutil_file/shutil_new.txt","/tmp/shutil_file/shutil_exist.txt")    #将shutil_new.txt文件复制为存在的文件shutil_exist.txt
print("*"*60)
os.system("cat /tmp/shutil_file/shutil_exist.txt")      #查看复制后的文件shutil_exist.txt的内容
执行结果:
[root@localhost 20170717]# ./shutil_cp_exist_file.py 
You don't want to learn python
************************************************************
Welcome to the Linux world
Now we start learning python

  2.3 存在文件不具有写权限复制

[root@localhost 20170717]# ll /tmp/shutil_file/shutil_exist.txt
-r--r--r--. 1 root root 56 Jun 27 05:30 /tmp/shutil_file/shutil_exist.txt
#!/usr/bin/env python3

import shutil
import os

shutil.copyfile("/tmp/shutil_file/shutil_new.txt","/tmp/shutil_file/shutil_exist.txt")
print("*"*60)
os.system("cat /tmp/shutil_file/shutil_exist.txt")
执行结果:
[chengd@localhost 20170717]$ ./shutil_cp_exist_file.py 
Traceback (most recent call last):
  File "./shutil_cp_exist_file.py", line 6, in <module>
    shutil.copyfile("/tmp/shutil_file/shutil_new.txt","/tmp/shutil_file/shutil_exist.txt")
  File "/usr/local/lib/python3.6/shutil.py", line 121, in copyfile
    with open(dst, 'wb') as fdst:
PermissionError: [Errno 13] Permission denied: '/tmp/shutil_file/shutil_exist.txt'

  注:在root用户下,无论文件是否具有写权限,root都可以写入文件。

  2.4 src和dst是同一个文件

#!/usr/bin/env python3

import shutil
import os

shutil.copyfile("/tmp/shutil_file/shutil_old.txt","/tmp/shutil_file/shutil_old.txt")
os.system("cat /tmp/shutil_file/shutil_old.txt")
执行结果:
[root@localhost 20170717]# ./shutil_cpsame.py 
Traceback (most recent call last):
  File "./shutil_cpsame.py", line 6, in <module>
    shutil.copyfile("/tmp/shutil_file/shutil_old.txt","/tmp/shutil_file/shutil_old.txt")
  File "/usr/local/lib/python3.6/shutil.py", line 104, in copyfile
    raise SameFileError("{!r} and {!r} are the same file".format(src, dst))
shutil.SameFileError: '/tmp/shutil_file/shutil_old.txt' and '/tmp/shutil_file/shutil_old.txt' are the same file

3、shutil.copymode(src,dst):仅拷贝权限;内容、组、用户均不变;dst目标文件要存在

[root@localhost 20170717]# ls -al /tmp/shutil_cpmode*
-rwxrwxrwx. 1 root   root   0 Jun 27 05:46 /tmp/shutil_cpmode1.txt
-rw-rw-r--. 1 chengd chengd 0 Jun 27 05:47 /tmp/shutil_cpmode2.txt
#!/usr/bin/env python3

import shutil
import os

os.system("ls -al /tmp/shutil_cpmode*")

shutil.copymode("/tmp/shutil_cpmode1.txt","/tmp/shutil_cpmode2.txt")
mode = "mode拷贝分割线"
print("\n{:*^60}\n".format(mode))
os.system("ls -al /tmp/shutil_cpmode*")
执行结果:
[root@localhost 20170717]# ./shutil_cpmode.py 
-rwxrwxrwx. 1 root   root   0 Jun 27 05:46 /tmp/shutil_cpmode1.txt
-rw-rw-r--. 1 chengd chengd 0 Jun 27 05:47 /tmp/shutil_cpmode2.txt

*************************mode拷贝分割线**************************

-rwxrwxrwx. 1 root   root   0 Jun 27 05:46 /tmp/shutil_cpmode1.txt
-rwxrwxrwx. 1 chengd chengd 0 Jun 27 05:47 /tmp/shutil_cpmode2.txt

4、shutil.copystat(src,dst):复制权限、最后访问时间、最后修改时间等

5、shutil.copy(src,dst):拷贝文件和权限;如果dst是目录的话,则会在dst目录中创建和src同名的文件且权限一致。

  5.1 正常拷贝文件,即dst是文件

#!/usr/bin/env python3

import shutil
import os

os.system("ls -al /tmp/shutil_cpmode*")
shutil.copy("/tmp/shutil_cpmode2.txt","/tmp/shutil_cpmode.txt")    #将shutil_cpmode2.txt拷贝为shutil_cpmode.txt
mode = "copy拷贝分割线"
print("\n{:*^60}\n".format(mode))
os.system("ls -al /tmp/shutil_cpmode*")
执行结果:
[root@localhost 20170717]# ./shutil_cp.py 
-rwxrwxrwx. 1 root   root   0 Jun 27 05:46 /tmp/shutil_cpmode1.txt
-rwxrwxrwx. 1 chengd chengd 0 Jun 27 05:47 /tmp/shutil_cpmode2.txt

*************************copy拷贝分割线**************************

-rwxrwxrwx. 1 root   root   0 Jun 27 05:46 /tmp/shutil_cpmode1.txt
-rwxrwxrwx. 1 chengd chengd 0 Jun 27 05:47 /tmp/shutil_cpmode2.txt
-rwxrwxrwx. 1 root   root   0 Jun 27 06:29 /tmp/shutil_cpmode.txt    #拷贝文件权限未变

  5.2 拷贝目标dst是目录

[root@localhost 20170717]# ll /root/tmp_dir/
total 0
#!/usr/bin/env python3

import shutil
import os

shutil.copy("/tmp/shutil_cpmode2.txt","/root/tmp_dir")    #dst是目录的拷贝;会在dst目录中创建和shutil_cpmode2.txt同名的文件且权限一致
os.system("ls -Al /root/tmp_dir")
执行结果:
[root@localhost 20170717]# ./shutil_cpdir.py 
total 0
-rwxrwxrwx. 1 root root 0 Jun 27 06:42 shutil_cpmode2.txt

6、shutil.copy2:类似shutil.copy,不过会将元数据也复制,实际上先调用shutil.copy,然后使用copystat。这类似于linux命令cp -p

#!/usr/bin/env python3

import shutil
import os

os.system("ls -al /tmp/shutil_cpmode*")
shutil.copy2("/tmp/shutil_cpmode2.txt","/tmp/shutil_cp2mode.txt")  #通过copy2将shutil_cpmode2.txt拷贝为shutil_cp2mode.txt
mode = "copy2拷贝分割线"
print("\n{:*^60}\n".format(mode))
os.system("ls -al /tmp/shutil_cp*")
执行结果:
[root@localhost 20170717]# ./shutil_cp2.py 
-rwxrwxrwx. 1 root   root   0 Jun 27 05:46 /tmp/shutil_cpmode1.txt
-rwxrwxrwx. 1 chengd chengd 0 Jun 27 05:47 /tmp/shutil_cpmode2.txt
-rwxrwxrwx. 1 root   root   0 Jun 27 06:29 /tmp/shutil_cpmode.txt

*************************copy2拷贝分割线**************************

-rwxrwxrwx. 1 root   root   0 Jun 27 05:47 /tmp/shutil_cp2mode.txt
-rwxrwxrwx. 1 root   root   0 Jun 27 05:46 /tmp/shutil_cpmode1.txt
-rwxrwxrwx. 1 chengd chengd 0 Jun 27 05:47 /tmp/shutil_cpmode2.txt
-rwxrwxrwx. 1 root   root   0 Jun 27 06:29 /tmp/shutil_cpmode.txt

7、shutil.copytree(src_dir,dst_dir,symlinks=False,ignore=None):递归拷贝目录文件

  symlinks=False:若是True时,复制时保持文件夹下的符号链接,若为False则在复制时在文件下生成物理副本来替换符号链接;默认False

  shutil.ignore_patterns(*patterns):shutil.copytree的辅助函数,可以通过正则指定不拷贝那些文件;

[root@localhost 20170717]# ll /tmp/
total 68
drwxr-xr-x. 2 root   root   149 Jun 26 18:01 20170704
drwxr-xr-x. 2 root   root    42 Jun 26 21:08 20170706
drwxr-xr-x. 2 root   root   144 Jun 27 00:08 20170707
drwxr-xr-x. 2 root   root    24 Jun 27 00:45 20170708
drwxr-xr-x. 2 root   root   139 Jun 27 04:52 20170712
drwxr-xr-x. 2 root   root   197 Jun 27 07:10 20170717
-rw-r--r--. 1 root   root    45 Jun 27 04:07 book.txt
lrwxrwxrwx. 1 root   root    11 Jun 27 07:04 passwd.txt -> /etc/passwd
drwxr-xr-x. 3 root   root    35 Jun 26 11:43 py_test1
-rwxr-xr-x. 1 root   root   266 Jun 26 14:34 pytest10.py
-rwxr-xr-x. 1 root   root   405 Jun 26 14:17 pytest11.py
-rwxr-xr-x. 1 root   root   321 Jun 26 14:42 pytest12.py
-rwxr-xr-x. 1 root   root   348 Jun 26 14:48 pytest13.py
-rwxr-xr-x. 1 root   root   150 Jun 26 15:08 pytest14.py
-rwxr-xr-x. 1 root   root    71 Jun 26 15:17 pytest15.py
-rwxr-xr-x. 1 root   root   146 Jun 26 11:16 pytest1.py
-rwxr-xr-x. 1 root   root    54 Jun 26 11:21 pytest2.py
-rwxr-xr-x. 1 root   root   112 Jun 26 11:36 pytest4.py
-rwxr-xr-x. 1 root   root   196 Jun 26 11:43 pytest5.py
-rwxr-xr-x. 1 root   root   140 Jun 26 11:51 pytest6.py
-rwxr-xr-x. 1 root   root   545 Jun 26 13:11 pytest7.py
-rwxr-xr-x. 1 root   root   395 Jun 26 13:30 pytest8.py
-rwxr-xr-x. 1 root   root    81 Jun 26 13:34 pytest9.py
-rwxr-xr-x. 1 root   root   230 Jun 26 11:10 pytest.py
-rwxrwxrwx. 1 root   root     0 Jun 27 05:47 shutil_cp2mode.txt
-rwxrwxrwx. 1 root   root     0 Jun 27 05:46 shutil_cpmode1.txt
-rwxrwxrwx. 1 chengd chengd   0 Jun 27 05:47 shutil_cpmode2.txt
-rwxrwxrwx. 1 root   root     0 Jun 27 06:29 shutil_cpmode.txt
drwxr-xr-x. 2 root   root    74 Jun 27 05:27 shutil_file
-rw-r--r--. 1 root   root    54 Jun 27 03:33 user.txt
View Code
#!/usr/bin/env python3

import shutil
import os

shutil.copytree("/tmp","/mnt/tmp_bak",ignore=shutil.ignore_patterns("*.py"))
mode = "copytree拷贝分割线"
print("\n{:*^60}\n".format(mode))
os.system("ls -Al /mnt/tmp_bak")
执行结果:
[root@localhost 20170717]# ./shutil_cptree.py 

***********************copytree拷贝分割线************************

total 12
drwxr-xr-x. 2 root root    6 Jun 26 18:01 20170704
drwxr-xr-x. 2 root root    6 Jun 26 21:08 20170706
drwxr-xr-x. 2 root root    6 Jun 27 00:08 20170707
drwxr-xr-x. 2 root root    6 Jun 27 00:45 20170708
drwxr-xr-x. 2 root root    6 Jun 27 04:52 20170712
drwxr-xr-x. 2 root root    6 Jun 27 07:09 20170717
-rw-r--r--. 1 root root   45 Jun 27 04:07 book.txt
drwxrwxrwt. 2 root root    6 Jun 26 15:37 .font-unix
drwxrwxrwt. 2 root root    6 Jun 26 15:37 .ICE-unix
-rw-r--r--. 1 root root 1088 Jun 27 05:36 passwd.txt
drwxr-xr-x. 3 root root   35 Jun 26 11:43 py_test1
-rwxrwxrwx. 1 root root    0 Jun 27 05:47 shutil_cp2mode.txt
-rwxrwxrwx. 1 root root    0 Jun 27 05:46 shutil_cpmode1.txt
-rwxrwxrwx. 1 root root    0 Jun 27 05:47 shutil_cpmode2.txt
-rwxrwxrwx. 1 root root    0 Jun 27 06:29 shutil_cpmode.txt
drwxr-xr-x. 2 root root   74 Jun 27 05:27 shutil_file
drwxrwxrwt. 2 root root    6 Jun 26 15:37 .Test-unix
-rw-r--r--. 1 root root   54 Jun 27 03:33 user.txt
drwxrwxrwt. 2 root root    6 Jun 26 15:37 .X11-unix
drwxrwxrwt. 2 root root    6 Jun 26 15:37 .XIM-unix
[root@localhost 20170717]# ll /mnt/tmp_bak/
total 12
drwxr-xr-x. 2 root root    6 Jun 26 18:01 20170704
drwxr-xr-x. 2 root root    6 Jun 26 21:08 20170706
drwxr-xr-x. 2 root root    6 Jun 27 00:08 20170707
drwxr-xr-x. 2 root root    6 Jun 27 00:45 20170708
drwxr-xr-x. 2 root root    6 Jun 27 04:52 20170712
drwxr-xr-x. 2 root root    6 Jun 27 07:09 20170717
-rw-r--r--. 1 root root   45 Jun 27 04:07 book.txt
-rw-r--r--. 1 root root 1088 Jun 27 05:36 passwd.txt
drwxr-xr-x. 3 root root   35 Jun 26 11:43 py_test1
-rwxrwxrwx. 1 root root    0 Jun 27 05:47 shutil_cp2mode.txt
-rwxrwxrwx. 1 root root    0 Jun 27 05:46 shutil_cpmode1.txt
-rwxrwxrwx. 1 root root    0 Jun 27 05:47 shutil_cpmode2.txt
-rwxrwxrwx. 1 root root    0 Jun 27 06:29 shutil_cpmode.txt
drwxr-xr-x. 2 root root   74 Jun 27 05:27 shutil_file
-rw-r--r--. 1 root root   54 Jun 27 03:33 user.txt
View Code

8、shutil.rmtree(path[,ignore_errors[,onerror]]):递归的删除文件

[root@localhost 20170717]# ll /mnt/tmp_bak/
total 12
drwxr-xr-x. 2 root root    6 Jun 26 18:01 20170704
drwxr-xr-x. 2 root root    6 Jun 26 21:08 20170706
drwxr-xr-x. 2 root root    6 Jun 27 00:08 20170707
drwxr-xr-x. 2 root root    6 Jun 27 00:45 20170708
drwxr-xr-x. 2 root root    6 Jun 27 04:52 20170712
drwxr-xr-x. 2 root root    6 Jun 27 07:09 20170717
-rw-r--r--. 1 root root   45 Jun 27 04:07 book.txt
-rw-r--r--. 1 root root 1088 Jun 27 05:36 passwd.txt
drwxr-xr-x. 3 root root   35 Jun 26 11:43 py_test1
-rwxrwxrwx. 1 root root    0 Jun 27 05:47 shutil_cp2mode.txt
-rwxrwxrwx. 1 root root    0 Jun 27 05:46 shutil_cpmode1.txt
-rwxrwxrwx. 1 root root    0 Jun 27 05:47 shutil_cpmode2.txt
-rwxrwxrwx. 1 root root    0 Jun 27 06:29 shutil_cpmode.txt
drwxr-xr-x. 2 root root   74 Jun 27 05:27 shutil_file
-rw-r--r--. 1 root root   54 Jun 27 03:33 user.txt
View Code
#!/usr/bin/env python3

import shutil
import os

shutil.rmtree("/mnt/tmp_bak")    #递归删除/mnt下的tmp_bak中的所有文件,包含tmp_bak目录本身
mode = "rmtree拷贝分割线"
print("\n{:*^60}\n".format(mode))
os.system("ls -Al /mnt/tmp_bak")
执行结果:
[root@localhost 20170717]# ./shutil_rmtree.py 

************************rmtree拷贝分割线*************************

ls: cannot access /mnt/tmp_bak: No such file or directory    #/mnt/tmp_bak已被删除

9、shutil.move(src,dst):递归的去移动文件,其实就是重命名;类似linux中的mv。

#!/usr/bin/env python3

import shutil
import os

os.system("ls -Al /tmp")
shutil.move("/tmp/book.txt","/tmp/books.txt")
mode = "move拷贝分割线"
print("\n{:*^60}\n".format(mode))
os.system("ls -Al /tmp")
执行结果:
[root@localhost 20170717]# ./shutil_move.py 
total 3
-rw-r--r--. 1 root   root    45 Jun 27 04:07 book.txt
drwxrwxrwt. 2 root   root     6 Jun 26 15:37 .font-unix
drwxrwxrwt. 2 root   root     6 Jun 26 15:37 .ICE-unix*************************move拷贝分割线**************************

total 3
-rw-r--r--. 1 root   root    45 Jun 27 04:07 books.txt
drwxrwxrwt. 2 root   root     6 Jun 26 15:37 .font-unix
drwxrwxrwt. 2 root   root     6 Jun 26 15:37 .ICE-unix

10、shutil.make_archive(base_name, format,...):打包压缩文件

  格式:shutil.make_archive(base_name, format[, root_dir[, base_dir, verbose, dry_run, owner, group, logger])

  base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
  format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
  root_dir: 要压缩的文件夹路径(默认当前目录)
  owner: 用户,默认当前用户
  group: 组,默认当前组
  logger: 用于记录日志,通常是logging.Logger对象

#!/usr/bin/env python3

import shutil
import os

shutil.make_archive("/mnt/tmp","gztar",root_dir="/tmp")    #将/tmp目录打包并压缩存放至/mnt下名为tmp
mode = "archive拷贝分割线"
print("\n{:*^60}\n".format(mode))
os.system("ls -Al /mnt")
执行结果:
[root@localhost 20170717]# ./shutil_archive.py 

************************archive拷贝分割线************************

total 8
-rw-r--r--. 1 root root 6930 Jun 27 08:19 tmp.tar.gz

 11、shutil.unpack_archive(filename, extract_dir=None, format=None):解压缩归档文件

  filename是存档的名称。

  extract_dir是解压缩目标目录的名称如果没有提供,则使用当前的工作目录。

  format是归档格式:“zip”、“tar”或“gztar”。或任何其他已注册的格式。如果没有提供,unpackarchive将使用文件扩展名。 

  如果没有找到,则会增加一个ValueError。

#!/usr/bin/env python3

import shutil
import os

shutil.unpack_archive("/mnt/tmpbak0718.tar.gz","/mnt/tmp20170718","gztar")
mode = "unpack_archive拷贝分割线"
print("\n{:*^60}\n".format(mode))
os.system("ls -Al /mnt")
执行结果:
[root@localhost 20170718]# ./shutil_unarchive.py 

************************unpack_archive拷贝分割线************************

total 28
drwxrwxrwt. 16 lzy  lzy  4096 Jun 27 08:35 tmp20170718
-rw-r--r--.  1 root root 6947 Jun 27 08:36 tmpbak0718.tar.gz
-rw-r--r--.  1 root root 6920 Jun 27 08:33 tmpbak.tar.gz
-rw-r--r--.  1 root root 6912 Jun 27 08:32 tmp.tar.gz

 

***********************************************************

 学习永远不晚。——高尔基

***********************************************************

 

posted @ 2017-07-18 21:00  chengd  阅读(867)  评论(0)    收藏  举报