本章介介绍了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/total4
-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/total8
-rw-r--r--. 1 root 960 Apr 22 16:57my.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
total4
-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 test10 total 4
11 -rw-r--r--. 1 root 2573 Apr 23 2017 CentOS-Base.repo12
13 In [38]: shutil.rmtree('/root/test')14
15 In [39]: ll16 total 12
17 -rw-------. 1 root 1468 Apr 16 21:03 anaconda-ks.cfg18 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
importosfor foldName,subfolders,filenames in os.walk('/root/'):print('The current folder is:' +foldName)for subfolder insubfolders:print('subfolder of' + foldName + ':' +subfolder)for filename infilenames:print('file inside' + foldName + ':' +filename)print('')
三.实践项目参考答案
1 #!/usr/bin/env python3.4
2 #coding:utf-8
3 importos4 importshutil5 importsend2trash6
7 #9.8.1
8 #拷贝指定格式文件到指定目录,下面程序是将/etc目录下所的.conf文件拷贝到/root/test/目录里。
9 src = '/etc/'
10 dst = '/root/test/'
11 ftype = '.conf'
12 count =013 for filename inos.listdir(src):14 iffilename.endswith(ftype):15 shutil.copy(src +filename,dst)16 count += 1
17 print('文件' + src + filename + '\t被拷贝到--->' + 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 inos.walk(dst):26 for files infilenames: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 importre4 importos5 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_end18 f_num.append('00' +str(i))19 fs_list.append(f_name)20 else:21 f_name = f_pre + '0' + str(i) +f_end22 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('目录中已有编号文件:\n%s' %yf_num)34
35 #fq_list为目录中缺失编号的文件名列表
36 #fx_list为当前目录中需要修改名称的文件列表
37 fq_list =[]38 fx_list =[]39 #定位缺失的编号文件并放入列表中
40 for a infs_list:41 if a not inyf_num:42 fq_list.append(a)43 print('缺少的文件编号是:\n%s' %fq_list)44
45 #查找目录中没有编号或不正连续的编号文件并放入列表中
46 for f_rename infdir_list:47 if f_rename not infs_list:48 fx_list.append(f_rename)49 print('需要修改的文件名有:\n%s' %fx_list)50
51 #更改文件名
52 for k infq_list:53 for v infx_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 importre4 importos5 fdir = '/root/github/shell/python3/py-9/test/'
6 fdir_list =os.listdir(fdir)7 fdir_f_count =len(fdir_list)8 print('当前目录的文件为:\n%s' %fdir_list)9 defgetFileformat(f_pre,f_num,f_end):10 fileformat = f_pre + f_num +f_end11 returnfileformat12 file_list =[]13 defgetTruefile():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 returnfile_list22 truefilelist =getTruefile()23 print('正确的文件编号应该是:\n%s' %truefilelist)24 lostnumfilelist =[]25 defgetLostnumfile(fdirlist,truelist):26 for lf intruelist:27 if lf not infdirlist:28 lostnumfilelist.append(lf)29 returnlostnumfilelist30 lostnumfile =getLostnumfile(fdir_list,file_list)31 print('缺失的文件编号为:\n%s' %lostnumfile)32
33 renamelist =[]34 defgetrenamefile(fdirlist,func):35 for a infdirlist:36 if a not infunc:37 renamelist.append(a)38 returnrenamelist39 renamefilelist =getrenamefile(fdir_list,file_list)40 print('需要修改的文件是\n%s' %renamefilelist)41
42 defrenamefile(func1,func2):43 for b infunc1:44 for c infunc2: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')