python编程快速上手之第9章实践项目参考答案

本章介介绍了shutil,zipfile模块的使用,我们先来认识一下这2个模块吧。

一.shutil模块

shutil模块主要用于对文件或文件夹进行处理,包括:复制,移动,改名和删除文件,在shutil模块中主要以下这么几个函数:

1.复制文件和文件夹

shutil模块提供了2个函数:shutil.copy()和shutil.copytree()

shutil.copy的语法格式:

copy(src, dst)

作用:

将src处的文件复制到dst路径中去,其中src,dst都是字符串形式的路径。如果dst是一个文件名,它将作为被复制文件的新名字,相当于把原路径的文件复制到新路径并改名。

举例:

将/etc/my.cnf 复制到/root/mysql中

In [12]: import shutil

In [13]: shutil.copy('/etc/my.cnf','/root/mysql/')
Out[13]: '/root/mysql/my.cnf'

In [15]: ll /root/mysql/
total 4
-rw-r--r--. 1 root 960 Apr 22 16:57 my.cnf

将/etc/my.cnf复制到/root/mysql并改名为mysql.cnf

In [16]: shutil.copy('/etc/my.cnf','/root/mysql/mysql.cnf')
Out[16]: '/root/mysql/mysql.cnf'

In [17]: ll /root/mysql/
total 8
-rw-r--r--. 1 root 960 Apr 22 16:57 my.cnf
-rw-r--r--. 1 root 960 Apr 22 17:00 mysql.cnf

shutil.copytree的语法格式:

copytree(src, dst)

作用:

复制整个文件夹。将src处的文件夹,包括它的所有文件和子文件夹,复制到路径dst处的文件夹。返回一个新复制的文件夹路径的字符串。

举例:

In [20]: shutil.copytree('/etc/yum.repos.d','/root/repo.back')
Out[20]: '/root/repo.back'

In [21]: ll /root/drwxr-xr-x. 2 root 4096 Apr 23  2017 repo.back/
drwxr-xr-x. 2 root 4096 Apr 23  2017 repo.bak/

注意:dst必须是一个系统中不存在目录,不然会报错:

In [20]: shutil.copytree('/etc/yum.repos.d','/root/repo.bak')
FileExistsError: [Errno 17] File exists: '/root/repo.bak'

2.文件和文件夹的移动和改名

shutil.move()

语法格式:

move(stc,dst)

作用:

将路径stc处的文件夹移动到路径dst,并返回新位置的绝对路径的字符串。

举例:

将/root/目录下的a.txt移动到/root/test/目录中

In [26]: shutil.move('/root/a.txt','/root/test/')
Out[26]: '/root/test/a.txt'

In [27]: ll /root/test
total 4
-rw-r--r--. 1 root 6 Apr 22 17:30 a.txt

注意:

如果dst指向一个文件夹,src文件将移动到dst中,并保持原来的文件名,前提是dst必须是系统中已经存在的目录。

如果目标文件中已存在相同名称的文件将被覆盖,需要注意。

3.删除文件和文件夹

在os模块中:

os.remove(path)可以删除一个文件

os.rmdir(path)可以删除一个空文件夹。

在shutil模块中:

shutil.rmtree(path)可以删除一个文件夹及其所有的内容。

语法格式:

os.rmdir(path)
shutil.rmtree(path)

举例:

 1 In [34]: os.remove('/root/test/a.txt')
 2 
 3 In [35]: ll /root/test/
 4 total 0
 5 
 6 In [36]: shutil.move('/root/CentOS-Base.repo','/root/test/')
 7 Out[36]: '/root/test/CentOS-Base.repo'
 8 
 9 In [37]: ll test
10 total 4
11 -rw-r--r--. 1 root 2573 Apr 23  2017 CentOS-Base.repo
12 
13 In [38]: shutil.rmtree('/root/test')
14 
15 In [39]: ll
16 total 12
17 -rw-------. 1 root 1468 Apr 16 21:03 anaconda-ks.cfg
18 drwxr-xr-x. 2 root   57 Apr 23  2017 download/
19 drwxr-xr-x. 2 root   37 Apr 22 17:00 mysql/
20 drwxr-xr-x. 6 root   95 Apr 16 21:58 py34/
21 drwxr-xr-x. 3 root   18 Apr 16 23:01 python/
22 drwxr-xr-x. 2 root 4096 Apr 23  2017 repo.back/
23 drwxr-xr-x. 2 root 4096 Apr 23  2017 repo.bak/

注意:

以上的删除都是永久的删除。为了安全起见最好使用send2trash第三方模块,它会将删除的文件放入回收站。在python3中已集成了这个模块。

send2trash用法:

import send2trash
send2trash(path)

二.遍历目录树

对文件的处理,尤其是批量操作就不得不对目录进行遍历。在python中os模块中的os.walk()函数就可以做到。

这个函数会递归遍历指定目录及子目录,返回一个3元组信息:当前目录名,子目录名,文件名,不包括 . 和 ..

常见用法:

#!/usr/bin/env python3.4
#coding:utf-8
import os
for foldName,subfolders,filenames in os.walk('/root/'):
    print('The current folder is: ' + foldName)
    for subfolder in subfolders:
        print('subfolder of ' + foldName + ':' + subfolder)
    for filename in filenames:
        print('file inside ' + foldName + ':' + filename)
    print('')

三.实践项目参考答案

 1 #!/usr/bin/env python3.4
 2 # coding:utf-8
 3 import os
 4 import shutil
 5 import send2trash
 6 
 7 # 9.8.1
 8 # 拷贝指定格式文件到指定目录,下面程序是将/etc目录下所的.conf文件拷贝到/root/test/目录里。
 9 src = '/etc/'
10 dst = '/root/test/'
11 ftype = '.conf'
12 count = 0
13 for filename in os.listdir(src):
14     if filename.endswith(ftype):
15         shutil.copy(src + filename,dst)
16         count += 1
17         print('文件 ' + src + filename + '	被拷贝到---> ' + dst + ' 目录下')
18 print("该目录下所有的 " + ftype + "文件已被拷贝到" + dst + "目录下")
19 print('共拷贝了 ' + str(count) + ' 个文件')
20 
21 # 9.8.2
22 # 搜索指定目录下大于100M的文件,打印出来并删除
23 # 可以手动创建一个指定大小的空文件做试验
24 # dd if=/dev/zero of=hello.txt bs=100M count=1
25 for foldname,subfolders,filenames in os.walk(dst):
26     for files in filenames:
27         if os.path.getsize(dst + files) / 1024 /1024 > 100:
28             print('大于100M的文件有:' + files + ' ' +  str(os.path.getsize(dst + files) / 1024 / 1024) +'Mb')
29             send2trash.send2trash(dst + files)

 9.8.3

假设test文件夹下有如下文件,文件是以spam开头加上数字编号,但是编号并不连续有缺失,而且有的并不包含数字,我们需要找出不符合文件名的文件并重新命名成连续编号的文件名。

(py34) [root@master test]# ls
spam002.txt  spam004.txt  spam006.txt  spam008.txt  spam999.txt
spam003.txt  spam005.txt  spam007.txt  spam011.txt  spamkkdf.txt

参考代码如下:

 1 #!/usr/bin/env python3.4
 2 # coding:utf-8
 3 import re
 4 import os
 5 fdir = '/root/python/py-9/test/'
 6 fdir_list = os.listdir(fdir)
 7 fdir_count = len(fdir_list)
 8 print(fdir_list)
 9 print('该目录下共有 %d 个文件' %fdir_count)
10 f_pre = 'spam'
11 f_num = []
12 f_end = '.txt'
13 fs_list = []
14 # 这里只假定文件数量小100的情况
15 for i in range(1,fdir_count + 1):
16     if i < 10:
17         f_name = f_pre + '00' + str(i) + f_end
18         f_num.append('00' + str(i))
19         fs_list.append(f_name)
20     else:
21         f_name = f_pre + '0' + str(i) + f_end
22         f_num.append('0' + str(i))
23         fs_list.append(f_name)
24 max_f_num = max(f_num)
25 print('该目录下文件最大的编号应该是: %s' %max_f_num)
26 print('正确的文件名应该是:')
27 print(fs_list)
28 
29 # 使用正则表达式搜索目录中已有编号的文件并存入列表yf_num中
30 re_num = 'd{3}'
31 yf_num = re.findall(f_pre + re_num + f_end,' '.join(fdir_list))
32 ra_num = re.findall(re_num,' '.join(fdir_list))
33 print('目录中已有编号文件:
%s' %yf_num)
34 
35 # fq_list为目录中缺失编号的文件名列表
36 # fx_list为当前目录中需要修改名称的文件列表
37 fq_list = []
38 fx_list = []
39 # 定位缺失的编号文件并放入列表中
40 for a in fs_list:
41     if a not in yf_num:
42         fq_list.append(a)
43 print('缺少的文件编号是:
%s' %fq_list)
44 
45 # 查找目录中没有编号或不正连续的编号文件并放入列表中
46 for f_rename in fdir_list:
47     if f_rename not in fs_list: 
48         fx_list.append(f_rename)
49 print('需要修改的文件名有:
%s' %fx_list)
50 
51 # 更改文件名
52 for k in fq_list:
53     for v in fx_list:
54         os.rename(fdir + v,fdir + k)
55         # 每当修完一个文件名应该更新一下这个列表
56         fx_list.remove(v)
57 print('改完名后的结果为:')
58 os.system('ls')

今天回来看看,决定用函数的方式来练习并实现,代码有了一些小的改进,上代码:

 1 #!/usr/bin/env python3.4
 2 # coding:utf-8
 3 import re
 4 import os
 5 fdir = '/root/github/shell/python3/py-9/test/'
 6 fdir_list = os.listdir(fdir)
 7 fdir_f_count = len(fdir_list)
 8 print('当前目录的文件为:
%s' % fdir_list)
 9 def getFileformat(f_pre,f_num,f_end):
10     fileformat = f_pre + f_num + f_end
11     return fileformat
12 file_list = []
13 def getTruefile():
14     for i in range(1,fdir_f_count + 1):
15         if i < 10:
16             f_format = getFileformat('spam','00' + str(i),'.txt')
17             file_list.append(f_format)
18         else:
19             f_format = getFileformat('spam','0' + str(i),'.txt')
20             file_list.append(f_format)
21     return file_list
22 truefilelist = getTruefile()
23 print('正确的文件编号应该是:
%s' %truefilelist)
24 lostnumfilelist = []
25 def getLostnumfile(fdirlist,truelist):
26     for lf in truelist:
27         if lf not in fdirlist:
28             lostnumfilelist.append(lf)
29     return lostnumfilelist
30 lostnumfile = getLostnumfile(fdir_list,file_list)
31 print('缺失的文件编号为:
%s' %lostnumfile)
32 
33 renamelist = []
34 def getrenamefile(fdirlist,func):
35     for a in fdirlist:
36         if a not in func:
37             renamelist.append(a)
38     return renamelist
39 renamefilelist = getrenamefile(fdir_list,file_list)
40 print('需要修改的文件是
%s' %renamefilelist)
41 
42 def renamefile(func1,func2):
43     for b in func1:
44         for c in func2:
45             os.rename(fdir + c,fdir + b)
46             func2.remove(c)
47 rename = renamefile(lostnumfile,renamefilelist)
48 os.chdir(fdir)
49 print('修改后的结果为:')
50 os.system('ls')
原文地址:https://www.cnblogs.com/mfyang/p/6749609.html