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

时间:2022-12-04 20:17:18

本章介介绍了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 []: import shutil

In []: shutil.copy('/etc/my.cnf','/root/mysql/')
Out[]: '/root/mysql/my.cnf' In []: ll /root/mysql/
total
-rw-r--r--. root Apr : my.cnf

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

In []: shutil.copy('/etc/my.cnf','/root/mysql/mysql.cnf')
Out[]: '/root/mysql/mysql.cnf' In []: ll /root/mysql/
total
-rw-r--r--. root Apr : my.cnf
-rw-r--r--. root Apr : mysql.cnf

shutil.copytree的语法格式:

copytree(src, dst)

作用:

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

举例:

In []: shutil.copytree('/etc/yum.repos.d','/root/repo.back')
Out[]: '/root/repo.back' In []: ll /root/drwxr-xr-x. root Apr repo.back/
drwxr-xr-x. root Apr repo.bak/

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

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

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

shutil.move()

语法格式:

move(stc,dst)

作用:

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

举例:

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

In []: shutil.move('/root/a.txt','/root/test/')
Out[]: '/root/test/a.txt' In []: ll /root/test
total
-rw-r--r--. root Apr : a.txt

注意:

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

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

3.删除文件和文件夹

在os模块中:

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

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

在shutil模块中:

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

语法格式:

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

举例:

 In []: os.remove('/root/test/a.txt')

 In []: ll /root/test/
total In []: shutil.move('/root/CentOS-Base.repo','/root/test/')
Out[]: '/root/test/CentOS-Base.repo' In []: ll test
total
-rw-r--r--. root Apr CentOS-Base.repo In []: shutil.rmtree('/root/test') In []: ll
total
-rw-------. root Apr : anaconda-ks.cfg
drwxr-xr-x. root Apr download/
drwxr-xr-x. root Apr : mysql/
drwxr-xr-x. root Apr : py34/
drwxr-xr-x. root Apr : python/
drwxr-xr-x. root Apr repo.back/
drwxr-xr-x. root Apr 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('')

三.实践项目参考答案

 #!/usr/bin/env python3.4
# coding:utf-8
import os
import shutil
import send2trash # 9.8.1
# 拷贝指定格式文件到指定目录,下面程序是将/etc目录下所的.conf文件拷贝到/root/test/目录里。
src = '/etc/'
dst = '/root/test/'
ftype = '.conf'
count = 0
for filename in os.listdir(src):
if filename.endswith(ftype):
shutil.copy(src + filename,dst)
count += 1
print('文件 ' + src + filename + '\t被拷贝到---> ' + dst + ' 目录下')
print("该目录下所有的 " + ftype + "文件已被拷贝到" + dst + "目录下")
print('共拷贝了 ' + str(count) + ' 个文件') # 9.8.2
# 搜索指定目录下大于100M的文件,打印出来并删除
# 可以手动创建一个指定大小的空文件做试验
# dd if=/dev/zero of=hello.txt bs=100M count=1
for foldname,subfolders,filenames in os.walk(dst):
for files in filenames:
if os.path.getsize(dst + files) / 1024 /1024 > 100:
print('大于100M的文件有:' + files + ' ' + str(os.path.getsize(dst + files) / 1024 / 1024) +'Mb')
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

参考代码如下:

 #!/usr/bin/env python3.4
# coding:utf-8
import re
import os
fdir = '/root/python/py-9/test/'
fdir_list = os.listdir(fdir)
fdir_count = len(fdir_list)
print(fdir_list)
print('该目录下共有 %d 个文件' %fdir_count)
f_pre = 'spam'
f_num = []
f_end = '.txt'
fs_list = []
# 这里只假定文件数量小100的情况
for i in range(1,fdir_count + 1):
if i < 10:
f_name = f_pre + '' + str(i) + f_end
f_num.append('' + str(i))
fs_list.append(f_name)
else:
f_name = f_pre + '' + str(i) + f_end
f_num.append('' + str(i))
fs_list.append(f_name)
max_f_num = max(f_num)
print('该目录下文件最大的编号应该是: %s' %max_f_num)
print('正确的文件名应该是:')
print(fs_list) # 使用正则表达式搜索目录中已有编号的文件并存入列表yf_num中
re_num = '\d{3}'
yf_num = re.findall(f_pre + re_num + f_end,' '.join(fdir_list))
ra_num = re.findall(re_num,' '.join(fdir_list))
print('目录中已有编号文件:\n%s' %yf_num) # fq_list为目录中缺失编号的文件名列表
# fx_list为当前目录中需要修改名称的文件列表
fq_list = []
fx_list = []
# 定位缺失的编号文件并放入列表中
for a in fs_list:
if a not in yf_num:
fq_list.append(a)
print('缺少的文件编号是:\n%s' %fq_list) # 查找目录中没有编号或不正连续的编号文件并放入列表中
for f_rename in fdir_list:
if f_rename not in fs_list:
fx_list.append(f_rename)
print('需要修改的文件名有:\n%s' %fx_list) # 更改文件名
for k in fq_list:
for v in fx_list:
os.rename(fdir + v,fdir + k)
# 每当修完一个文件名应该更新一下这个列表
fx_list.remove(v)
print('改完名后的结果为:')
os.system('ls')

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

 #!/usr/bin/env python3.4
# coding:utf-8
import re
import os
fdir = '/root/github/shell/python3/py-9/test/'
fdir_list = os.listdir(fdir)
fdir_f_count = len(fdir_list)
print('当前目录的文件为:\n%s' % fdir_list)
def getFileformat(f_pre,f_num,f_end):
fileformat = f_pre + f_num + f_end
return fileformat
file_list = []
def getTruefile():
for i in range(1,fdir_f_count + 1):
if i < 10:
f_format = getFileformat('spam','' + str(i),'.txt')
file_list.append(f_format)
else:
f_format = getFileformat('spam','' + str(i),'.txt')
file_list.append(f_format)
return file_list
truefilelist = getTruefile()
print('正确的文件编号应该是:\n%s' %truefilelist)
lostnumfilelist = []
def getLostnumfile(fdirlist,truelist):
for lf in truelist:
if lf not in fdirlist:
lostnumfilelist.append(lf)
return lostnumfilelist
lostnumfile = getLostnumfile(fdir_list,file_list)
print('缺失的文件编号为:\n%s' %lostnumfile) renamelist = []
def getrenamefile(fdirlist,func):
for a in fdirlist:
if a not in func:
renamelist.append(a)
return renamelist
renamefilelist = getrenamefile(fdir_list,file_list)
print('需要修改的文件是\n%s' %renamefilelist) def renamefile(func1,func2):
for b in func1:
for c in func2:
os.rename(fdir + c,fdir + b)
func2.remove(c)
rename = renamefile(lostnumfile,renamefilelist)
os.chdir(fdir)
print('修改后的结果为:')
os.system('ls')