Python 基础实战

1. 概述

本节实现一个文件管理程序,该程序会使用到如下知识点:

  • 函数
  • 面向对象
    • 采用面向对象的程序设计方法对数据建模
  • 异常处理
    • 使用异常处理和文件相关的错误,例如文件不存在
  • 模块
    • 程序由多个源文件构成,每个源文件实现一个功能模块
  • os 模块
    • 需要使用 os 模块提供的方法
  • sys 模块
    • 需要使用 os 模块提供的方法
  • 文件访问

2. 程序功能

2.1 概述

文件管理程序提供了如下功能:

  • 列出目录下的文件名
  • 打印文件内容
  • 复制文件
  • 删除文件

文件管理程序是一个命令行程序,读取用户输入命令,然后执行返回命令执行结果。文件管理程序支持如下命令:

命令 功能
ls dir 列出目录 dir 下的文件
cat file 打印文件 file 的内容
cp src dst 复制源文件 src 到目标文件 dst
rm file 删除文件 file
exit 退出程序

2.2 测试文件 test.txt

本节需要使用一个用于测试的文本文件 test.txt,内容如下:

www
imooc
com

2.3 示例

下面的命令演示了文件管理程序的用法:

2.3.1 启动程序

C:> python main.py
> 
  • 在第 1 行,程序的主文件是 main.py,启动程序
  • 在第 2 行,程序启动后,打印提示符 >,等待用户输入命令

2.3.2 输入命令 help

> help
exit          - exit program
cat file      - print file
ls            - list file in current dir
ls dir        - list file in dir
cp src dst    - copy file
rm file       - remove file
  • 在第 1 行,输入命令 help,功能是打印各个命令的用法

2.3.3 输入命令 cat

> cat test.txt
www
imooc
com
  • 在第 1 行,输入命令 cat test.txt,功能是打印文件 test.txt 的内容

2.3.4 输入命令 ls

> ls
main.py
test.txt
  • 在第 1 行,输入命令 ls,功能是列出当前目录下的文件
> ls C:
Documents and Settings
Program Files
Program Files (x86)
ProgramData
System Volume Information
Users
Windows
  • 在第 1 行,输入命令 ls C:,功能是列出 C 盘根目录下的文件

2.3.5 输入命令 cp

> cp test.txt test.bak
> ls
main.py
test.txt
test.bak
  • 在第 1 行,输入命令 cp test.txt test.bak,功能是将文件 test.txt 复制到 test.bak
  • 在第 2 行,输入命令 ls,列出当前目录下的文件,发现新增了一个文件 test.bak

2.3.6 输入命令 rm

> rm test.bak
> ls
main.py
test.txt
  • 在第 1 行,输入命令 rm test.bak,功能是删除文件 test.bak
  • 在第 2 行,输入命令 ls,列出当前目录下的文件,发现文件 test.bak 被删除了

2.3.6 输入命令 exit

> exit
C:>
  • 在第 1 行,输入命令 exit,功能是退出程序
  • 在第 2 行,返回到 DOS 命令行模式

2.4 错误处理

文件管理程序提供了错误处理功能,如果执行某条命令时发生了错误,例如文件不存在,仅仅终止该命令,而不是终止程序。

> cat non-exist-file
[Errno 2] No such file or directory: 'non-exisit-file'
>
  • 在第 1 行,打印文件 non-exist-file,该文件并不存在,cat 命令运行会出错
  • 在第 2 行,cat 命令执行中止,打印错误提示信息
  • 在第 3 行,cat 命令中止后,打印命令提示符,等待用户输入新的命令

3. 程序框架

文件管理程序由多个源文件构成,它们的功能如下:

源文件 功能
main.py 主控程序,读取用户的命令并执行
command.py 定义类 Command,定义了命令的接口
help.py 定义类 HelpCommand,实现 help 命令的功能
ls.py 定义类 LsCommand,实现 ls 命令的功能
cat.py 定义类 CatCommand,实现 cat 命令的功能
cp.py 定义类 CpCommand,实现 cp 命令的功能
rm.py 定义类 RmCommand,实现 rm 命令的功能

4. 实现主控程序

编写文件 main.py,读取用户的命令并执行:

import sys
import cat
import ls
import cp
import rm
import help
  • 在第 1 行导入 Python 内置的 sys 模块
  • 在第 2 行到第 6 行导入用户自定义的 5 个模块
    • cat 模块中定义了类 CatCommand,实现 cat 命令的功能
    • ls 模块中定义了类 LsCommand,实现 ls 命令的功能
    • cp 模块中定义了类 CpCommand,实现 cp 命令的功能
    • rm 模块中定义了类 RmCommand,实现 rm 命令的功能
    • help 模块中定义了类 HelpCommand,实现 help 命令的功能
def readAndExecute():
    print('> ', end = '')
    line = input()
    args = line.split()
    if len(args) == 0:
        return
  • 在第 1 行,定义函数 readAndExecute(), 读取用户输入的命令并执行
  • 在第 2 行,打印提示符 >
  • 在第 3 行,读取用户输入的命令
  • 在第 4 行,将用户输入的命令分割为多个单词
    • 假设用户输入命令是 cp test.txt test.bak
    • 经过 split() 后,args = [‘cp’, ‘test.txt’, ‘test.bak’]
    arg0 = args[0]
    if arg0 == 'exit':
        sys.exit()
    elif arg0 == 'cat':
        command = cat.CatCommand(args)
    elif arg0 == 'ls':
        command = ls.LsCommand(args)
    elif arg0 == 'cp':
        command = cp.CpCommand(args)
    elif arg0 == 'rm':
        command = rm.RmCommand(args)
    else:
        command = help.HelpCommand(args)

    command.execute()
  • 第 0 个参数是命令的名称,根据命令的名称构造相应的命令对象
    • 如果命令是 exit,调用 sys 模块的 exit 方法退出程序
    • 如果命令是 cat,使用 cat 模块中定义的类 CatCommand 实例化一个命令对象
    • 如果命令是 ls,使用 ls 模块中定义的类 LsCommand 实例化一个命令对象
    • 如果命令是 cp,使用 cp 模块中定义的类 CpCommand 实例化一个命令对象
    • 如果命令是 rm,使用 rm 模块中定义的类 RmCommand 实例化一个命令对象
    • 如果不是以上命令,使用 help 模块中定义的类 HelpCommand 实例化一个命令对象
  • 在最后,调用命令对象 command 的 execute 方法执行命令
while True:
    try:
        readAndExecute()
    except IOError as error:
        print(error)
  • 在第 1 行,定义循环,循环反复执行函数 readAndExecute()
  • 执行函数 readAndExecute 时,可能会出现 IOError
    • 在 try 语句中执行 readAndExecute
    • 使用 except 语句捕获执行过程中的 IOError,并打印 error
  • 注意,当 readAndExecute 出现异常时,仅仅终止 readAndExecute,而不是终止程序

5. 实现命令接口

编写文件 command.py 实现命令的接口:

class Command:
    def __init__(self, args):
        self.args = args

    def execute(self):
        print('Command.execute')
  • 在第 1 行,定义类 Command,描述了一个命令的接口
    • __init__ 方法,使用参数数组 args 构造一个命令
    • execute 方法,执行命令的功能,这里只提供了一个接口
  • 具体的命令如 LsCommand 继承类 Command,实现 execute 方法

6. 实现 help 命令

编写文件 help.py 实现 help 命令:

from command import Command

class HelpCommand(Command):
    def __init__(self, args):
        Command.__init__(self, args)

    def execute(self):
        print('exit          - exit program')
        print('cat file      - print file')
        print('ls            - list file in current dir')
        print('ls dir        - list file in dir')
        print('cp src dst    - copy file')
        print('rm file       - remove file')       
  • 在第 1 行,从 command 模块中导入类 Command
  • 在第 3 行,定义类 HelpCommand,继承于类 Command
  • 在第 5 行,调用父类的构造函数
  • 在第 7 行,定义 execute 方法,打印各个命令的功能

7. 实现 ls 命令

编写文件ls.py 实现 ls 命令:

from command import Command
import os

class LsCommand(Command):
    def __init__(self, args):
        Command.__init__(self, args)

    def usage(self):
        print('ls            - list file in current dir')
        print('ls dir        - list file in dir')
  • 在第 1 行,从 command 模块中导入类 Command
  • 在第 3 行,定义类 HelpCommand,继承于类 Command
  • 在第 5 行,调用父类的构造函数
  • 在第 7 行,定义方法 usage 打印 ls 命令的功能
    def execute(self):
        if len(self.args) == 1:
            path = '.'
        elif len(self.args) == 2:
            path = self.args[1]
        else:
            self.usage()
            return
  • 如果执行的命令是 ls,则设置 path 为 ‘.’,列出当前目录下的文件
  • 如果执行的命令是 ls dir,则设置 path 为 args[1],列出指定目录下的文件
        entries = os.listdir(path)
        for entry in entries:
            print(entry)
  • 调用 os 模块的 listdir 方法,列出目录 path 下的文件

8. 实现 cat 命令

编写文件 cat.py,定义类 CatCommand 用于实现 cat 命令的功能:

from command import Command

class CatCommand(Command):
    def __init__(self, args):
        Command.__init__(self, args)

    def usage(self):
        print('cat file      - print file')
  • 在第 1 行,从 command 模块中导入类 Command
  • 在第 3 行,定义类 HelpCommand,继承于类 Command
  • 在第 5 行,调用父类的构造函数
  • 在第 7 行,定义方法 usage 打印 cat 命令的功能
    def execute(self):
        if len(self.args) != 2:
            self.usage()
            return

        path = self.args[1]
  • 如果命令为 cat file,则设置 path 为 args[1]
        file = open(path)
        for line in file:
            print(line, end = '')
        file.close() 
  • 使用 for 循环遍历文件的每一行,并输出

9. 实现 cp 命令

编写文件 cp.py,定义类 CpCommand 用于实现 cp 命令的功能

from command import Command

class CpCommand(Command):
    def __init__(self, args):
        Command.__init__(self, args)

    def usage(self):
        print('cp src dst    - copy file')
  • 在第 1 行,从 command 模块中导入类 Command
  • 在第 3 行,定义类 CpCommand,继承于类 Command
  • 在第 5 行,调用父类的构造函数
  • 在第 7 行,定义方法 usage 打印 cp 命令的功能
    def execute(self):
        if len(self.args) != 3:
            self.usage()
            return

        src_path = self.args[1]
        dst_path = self.args[2]
  • 设置 src_path 为 args[1]
  • 设置 dst_path 为 args[2]
        src_file = open(src_path, 'r')
        dst_file = open(dst_path, 'w')
        for line in src_file:
            dst_file.write(line)
        src_file.close()
        dst_file.close()
  • 以只读方式打开 src_path,以只写方式打开 dst_path
  • 遍历源文件 src_file 的每一行,将其写入到 dst_file 中

10. 实现 rm 命令

编写文件 rm.py,定义类 RmCommand 用于实现 rm 命令的功能

from command import Command
import os

class RmCommand(Command):
    def __init__(self, args):
        Command.__init__(self, args)

    def usage(self):
        print('rm file       - remove file')
  • 在第 1 行,从 command 模块中导入类 Command
  • 在第 3 行,定义类 RmCommand,继承于类 Command
  • 在第 5 行,调用父类的构造函数
  • 在第 7 行,定义方法 usage 打印 rm 命令的功能
    def execute(self):
        if len(self.args) != 2:
            self.usage()
            return

        path = self.args[1]
        os.remove(path)
  • 调用 os 模块的 remove 方法删除文件