解决问题
我们已经探索了 Python 语言中的许多部分,现在我们将通过设计并编写一款程序来了解如何把这些部分组合到一起。这些程序一定是能做到一些有用的事情。这节的Python教程就是教大家方法去学习如何靠你自己来编写一份 Python 脚本。
问题
我们希望解决的问题如下:
我想要一款程序来备份我所有的重要文件。
虽然这是一个简单的问题,但是其中并没有足够的信息有助于让我们开始规划一份解决方案。我们需要进行一些分析(Analysis)。例如,我们应该如何指定哪些文件是我们需要备份的?它们应该如何进行备份?储存到哪里?
在正确地分析了这些问题过后,我们便开始设计(Design)我们的程序。我们将列出一份关于我们的程序应如何运转的清单。在这个案例中,我已经编写了如下清单来说明我将如何工作。如果由你来设计程序,你可能不会做出同样的分析,因为每个人都有其自己的行事方式,所以出现不同是完全正常、且正确的。
- 需要备份的文件与目录应在一份列表中予以指定。
- 备份必须存储在一个主备份目录中。
- 备份文件将打包压缩成 zip 文件。
- zip 压缩文件的文件名由当前日期与时间构成。
- 我们使用在任何 GNU/Linux 或 Unix 发行版中都会默认提供的标准
zip
命令进行打包。在这里你需要了解到只要有命令行界面,你就可以使用任何需要用到的压缩或归档命令。
针对 Windows 用户的提示
Windows 用户可以从 GnuWin32 项目页面 上下载并安装
zip
命令,并将C:Program FilesGnuWin32in
添加至你的系统的PATH
环境变量中,这一操作过程与我们为使系统识别 Python 命令本身所做的事情相同。
解决方案
由于我们的程序设计方案现在已经相当稳定,我们便可以开始编写代码,这个过程我们称之为实现(Implementation)我们的解决方案。
将下述代码保存为 backup_ver1.py
:
import os import time # 1. 需要备份的文件与目录将被 # 指定在一个列表中。 # 例如在 Windows 下: # source = ['"C:\My Documents"', 'C:\Code'] # 又例如在 Mac OS X 与 Linux 下: source = ['/Users/swa/notes'] # 在这里要注意到我们必须在字符串中使用双引号 # 用以括起其中包含空格的名称。 #2. 备份文件必须存储在一个 #主备份目录中 #例如在 Windows 下: # target_dir = 'E:\Backup' # 又例如在 Mac OS X 和 Linux 下: target_dir = '/Users/swa/backup' # 要记得将这里的目录地址修改至你将使用的路径 # 3. 备份文件将打包压缩成 zip 文件。 # 4. zip 压缩文件的文件名由当前日期与时间构成。 target = target_dir + os.sep + time.strftime('%Y%m%d%H%M%S') + '.zip' # 如果目标目录还不存在,则进行创建 if not os.path.exists(target_dir): os.mkdir(target_dir) # 创建目录 # 5. 我们使用 zip 命令将文件打包成 zip 格式 zip_command = 'zip -r {0} {1}'.format(target, ' '.join(source)) # 运行备份 print('Zip command is:') print(zip_command) print('Running:') if os.system(zip_command) == 0: print('Successful backup to', target) else: print('Backup FAILED') 输出: $ python backup_ver1.py Zip command is: zip -r /Users/swa/backup/20140328084844.zip /Users/swa/notes Running: adding: Users/swa/notes/ (stored 0%) adding: Users/swa/notes/blah1.txt (stored 0%) adding: Users/swa/notes/blah2.txt (stored 0%) adding: Users/swa/notes/blah3.txt (stored 0%) Successful backup to /Users/swa/backup/20140328084844.zip
现在,我们正处于测试(Testing)阶段,在这一阶段我们测试我们的程序是否能正常工作。如果其行为不符合我们的预期,那么我们需要对我们的程序进行 Debug 工作,也就是说,移除程序中的 Bug(错误)。
如果上面的程序不能够正常工作,复制打印在 Zip command is
后面的命令,将其粘贴至 shell(在 GNU/Linux 与 Mac OS X 环境中)或 cmd
(对于 Windows 环境),看看存在什么错误并尝试将其修复。同时你还需要检查 zip 命令手册来看看是不是哪里存在错误。如果这条命令成功运行,那么可能是错误可能存在在 Python 程序本身之中,因此你需要检查你的程序是否如上面所展示那番。
它是如何工作的
你会注意到我们是如何一步步将我们的设计转化为代码的。
我们首先导入 os
与 time
模块以准备使用它们。然后,我们在 source
列表中指定我们需要备份的文件与目录。我们需要存储我们所有备份文件的目标目录在 target_dir
变量中予以指定。我们将要创建的 zip 归档文件的名字由当前日期与时间构成,在这里通过 time.strftime()
python函数来创建。文件名将以 .zip
作为扩展名,并存储在 target_dir
目录中。
在这里要注意 os.sep
变量的使用方式——它将根据你的操作系统给出相应的分隔符,在 GNU/Linux 与 Unix 中它会是 '/'
,在 Windows 中它会是 '\'
,在 Mac OS 中它会是 ':'
。使用 os.sep
而非直接使用这些字符有助于使我们的程序变得可移植,从而可以在上述这些系统中都能正常工作。
time.strftime()
函数会遵循某些格式(Specification),其中一种就如我们在上方程序中所使用的那样。%Y
将被替换成带有具体世纪的年份。%m
将会被替换成以 01
至 12
的十进制数所表示的月份。有关这些格式的全部列表可以在 Python 参考手册中查询到。
我们使用连接(Concatenates)字符串的加法(+
)运算符来创建目标 zip 文件的文件名,也就是说,它将两个字符串连接到一起并返回一个新的字符串。然后,我们创建了一串字符串 zip_command
,其中包括了我们要执行的命令。如果这条命令不能正常工作,你可以把它拷贝到 Shell(GNU/Linux 终端或 DOS 提示符)中进行检查。
我们使用的 zip
命令会有一些选项与参数需要传递。-r
选项用以指定 zip 命令应该递归地(Recursively)对目录进行工作,也就是说它应该包括所有的子文件夹与其中的文件。这两个选项结合到一起并可以指定一个快捷方式作 -qr
。选项后面跟着的是将要创建的 zip 文件的名称,再往后是需要备份的文件与目录的列表。我们通过使用已经讨论过并已了解该如何运用的的字符串方法 join
来将列表 source
转换成字符串。
随后,我们终于可以运行这一使用了 os.system
函数的命令,这一函数可以使命令像是从系统中运行的。也就是说,从 shell 中运行的——如果运行成功,它将返回 0
,如果运行失败,将返回一个错误代码。
根据命令运行的结果是成功还是失败,我们将打印出与之相应的信息来告诉你备份的结果究竟如何。
就是这样,我们便创建了一份用以备份我们的重要文件的脚本!
针对 Windows 用户的提示
除了使用双反斜杠转义序列,你还可以使用原始字符串。例如使用
'C:\Documents'
或r'C:Documents'
。然而,不要使用'C:Documents'
,因为它将被识别为你使用了一个未知的转义序列D
来结束路径的输入。
现在,我们已经拥有了一份可以正常工作的备份脚本,我们可以在任何我们需要备份文件的时候使用它。这被称作软件的操作(Operation)或部署(Deployment)阶段。
上面所展示的程序能够正常工作,但是(通常)第一个程序都不会按照你所期望的进行工作。可能是因为你没有正确地设计程序,或如果你在输入代码时出现了错误。出现这些情况时,在恰当的时候,你需要回到设计阶段,或者你需要对你的程序进行 Debug 工作。