项目四:将带有美国风格日期的文件改名为欧洲风格日期
背景
假定你的老板用电子邮件发给你上千个文件,文件名包含美国风格的日期(MM-DD-YYYY),需要将它们改名为欧洲风格的日期(DD-MM-YYYY)。手工完成这个无聊的任务可能需要几天时间!让我们写一个程序来完成它。
参考思路
下面是程序要做的事:
- 检查当前工作目录的所有文件名,寻找美国风格的日期。
- 如果找到,将该文件改名,交换月份和日期的位置,使之成为欧洲风格。
这意味着代码需要做下面的事情: - 创建一个正则表达式,可以识别美国风格日期的文本模式。
- 调用os.listdir(),找出工作目录中的所有文件。
- 循环遍历每个文件名,利用该正则表达式检查它是否包含日期。
- 如果它包含日期,用shutil.move()对该文件改名。
练习内容
- shutil 模块:复制、移动、改名和删除文件
shutil.copy(source, destination) //复制一个文件
shutil.copytree(source, destination) //复制整个文件夹
shutil.move(source, destination) //移动文件、文件夹(谨慎使用,小心覆写)
os.unlink(path) //将删除path 处的文件
os.rmdir(path) //将删除path 处的文件夹(该文件夹必须为空,其中没有任何文件和文件夹)
shutil.rmtree(path) //将删除path 处的文件(包含的所有文件和文件夹都会被删除)
在程序中使用这些函数时要小心!可以第一次运行程序时,注释掉这些调用,并且加上print()调用,显示会被删除的文件。这样做是一个好主意。在确定程序按照你的意图工作后, 删除print(filename) 代码行, 取消os.unlink(filename)代码行的注释。然后再次运行该程序,实际删除这些文件。
import os
for filename in os.listdir():
if filename.endswith('.rxt'):
#os.unlink(filename)
print(filename)
- send2trash 模块安全地删除
删除文件和文件夹的更好方法,是使用第三方的send2trash 模块
pip install send2trash,安装该模块
send2trash.send2trash(filename)//将文件夹和文件发送到计算机的垃圾箱或回收站,而不是永久删除它们 - os.walk() 遍历目录树
import os
for folderName, subfolders, filenames in os.walk('C:\\delicious'):
print('The current folder is ' + folderName)
for subfolder in subfolders:
print('SUBFOLDER OF ' + folderName + ': ' + subfolder)
for filename in filenames:
print('FILE INSIDE ' + folderName + ': '+ filename)
print('')
range(),os.walk()在循环的每次迭代中,返回3 个值:
1.当前文件夹名称的字符串。
2.当前文件夹中子文件夹的字符串的列表。
3.当前文件夹中文件的字符串的列表。
所谓当前文件夹,是指for 循环当前迭代的文件夹。程序的当前工作目录,不会因为os.walk()而改变。
- zipfile 模块压缩文件
要读取ZIP 文件的内容,首先必须创建一个ZipFile 对象。ZipFile 对象在概念上与File 对象相似。
zipfile.ZipFile() //创建一个ZipFile对象
namelist() //返回ZIP 文件中包含的所有文件和文件夹
的字符串的列表
getinfo() //返回一个关于特定文件的ZipInfo 对象
ZipInfo 对象有自己的属性,诸如表示字节数的file_size和compress_size,它们分别表示原来文件大小和压缩后文件大小。ZipFile 对象表示整个归档文件,而ZipInfo 对象则保存该归档文件中每个文件的有用信息。
extractall() //从ZIP 文件中解压缩所有文件和文件夹
extract()//从ZIP 文件中解压缩单个文件
要创建你自己的压缩ZIP 文件,必须以“写模式”打开ZipFile 对象,即传入’w’作为第二个参数
**write()**传入一个路径,会压缩该路径所指的文件,将它加到ZIP 文件中。第二个参数是“压缩类型”参数,它告诉计算机使用怎样的算法来压缩文件。可将这个值设置为zipfile.ZIP_DEFLATED
import zipfile
newZip = zipfile.ZipFile('new.zip', 'w')
newZip.write('spam.txt', compress_type=zipfile.ZIP_DEFLATED)
newZip.close()
具体实现
第1 步:为美国风格的日期创建一个正则表达式
程序的第一部分需要导入必要的模块,并创建一个正则表达式,它能识别MM-DD-YYYY 格式的日期。
在为这些文件改名之前,需要确定哪些文件要改名。文件名如果包含spam4-4-1984.txt 和01-03-2014eggs.zip 这样的日期,就应该改名,而文件名不包含日期的应该忽略,诸如littlebrother.epub。
可以用正则表达式来识别该模式。
第2 步:识别文件名中的日期部分
接下来,程序将循环遍历os.listdir()返回的文件名字符串列表,用这个正则表达式匹配它们。文件名不包含日期的文件将被忽略。如果文件名包含日期,匹配的文本将保存在几个变量中。。这些变量中的字符串将在下一步中使用,用于构成欧洲风格的文件名。
为了让分组编号直观,请尝试从头阅读该正则表达式,每遇到一个左括号就计数加一。不要考虑代码,只是写下该正则表达式的框架。这有助于使分组变得直观,例如
第3 步:构成新文件名,并对文件改名
作为最后一步,连接前一步生成的变量中的字符串,得到欧洲风格的日期:日期在月份之前。
实现代码:
#! python3
# renameDates.py - Renames filenames with American MM-DD-YYYY date format
# to European DD-MM-YYYY.
import shutil, os, re
# Create a regex that matches files with the American date format.
datePattern = re.compile(r"""^(.*?) # all text before the date
((0|1)?\d)- # one or two digits for the month
((0|1|2|3)?\d)- # one or two digits for the day
((19|20)\d\d) # four digits for the year
(.*?)$ # all text after the date
""", re.VERBOSE)
# Loop over the files in the working directory.
for amerFilename in os.listdir('.'):
mo = datePattern.search(amerFilename)
# Skip files without a date.
if mo == None:
continue
# Get the different parts of the filename.
beforePart = mo.group(1)
monthPart = mo.group(2)
dayPart = mo.group(4)
yearPart = mo.group(6)
afterPart = mo.group(8)
# Form the European-style filename.
euroFilename = beforePart + dayPart + '-' + monthPart + '-' + yearPart +afterPart
# Get the full, absolute file paths.
absWorkingDir = os.path.abspath('.')
amerFilename = os.path.join(absWorkingDir, amerFilename)
euroFilename = os.path.join(absWorkingDir, euroFilename)
# Rename the files.
print('Renaming "%s" to "%s"...' % (amerFilename, euroFilename))
#shutil.move(amerFilename, euroFilename) # uncomment after testing