python核心编程2 第九章 练习

9–1. 文件过滤. 显示一个文件的所有行, 忽略以井号( # )开头的行. 这个字符被用做Python , Perl, Tcl, 等大多脚本文件的注释符号.附加题: 处理不是第一个字符开头的注释.

1 filename = input("输入文件名:")
2 with open(filename) as f:
3     for i in f:
4         if i.startswith('#'):
5             continue
6         else:
7             print(i, end='')

9–2. 文件访问. 提示输入数字 N 和文件 F, 然后显示文件 F 的前 N 行.

1 num = int(input("输入数字:"))
2 filename = input("输入文件名:")
3 with open(filename) as f:
4     for i, j in enumerate(f):
5         if i == (num):
6             break
7         else:
8             print(j, end='')

9–3. 文件信息. 提示输入一个文件名, 然后显示这个文本文件的总行数.

1 filename = input('输入文件名:')
2 with open(filename) as f:
3     allline = f.readlines()
4     print(len(allline))

9–4. 文件访问. 

写一个逐页显示文本文件的程序. 提示输入一个文件名, 每次显示文本文件的 25 行, 暂停并向用户提示”按任意键继续.”, 按键后继续执行.

1 filename = input("输入文件名:")
2 num = 25
3 with open(filename) as f:
4     for i, j in enumerate(f, 1):
5         if i == num:
6             space = input("输入任意字符回车:")
7             num += 25
8         else:
9             print(j, end='')

9-5 考试成绩,改进你的考试成绩问题(练习5-3和6-4),要求能从多个文件中读入考试成绩。文件的数据格式由你自己决定。

 1 filename = input("输入文件名:")
 2 with open(filename) as f:
 3     for i in f:
 4         i = i.strip()
 5         if int(i) < 60:
 6             print("F")
 7         elif int(i) < 70:
 8             print("D")
 9         elif int(i) < 80:
10             print("C")
11         elif int(i) < 90:
12             print("B")
13         elif int(i) <= 100:
14             print("A")
15         else:
16             print("%s不在范围" % i)

9–6. 文件比较. 写一个比较两个文本文件的程序. 如果不同, 给出第一个不同处的行号和列号.

 1 def file(filename1, filename2):
 2     with open(filename1) as f1:
 3         f1alllines = f1.readlines()
 4 
 5     with open(filename2) as f2:
 6         f2alllines = f2.readlines()
 7 
 8     minlen1 = min(len(f1alllines), len(f2alllines))
 9     for i in range(minlen1):
10         if f1alllines[i] != f2alllines[i]:
11 
12             minlen2 = min(len(f1alllines[i]), len(f2alllines))
13             for j in range(minlen2):
14                 if f1alllines[i][j] != f2alllines[i][j]:
15                     return '不同行号: %s' % (i+1), '不同列号: %s' % (j+1)
16     return '文件相同'
17 
18 if __name__ == '__main__':
19     filename1 = input("输入文件名1:")
20     filename2 = input("输入文件名2:")
21     print(file(filename1, filename2))

9–7. 解析文件. Win32 用户: 创建一个用来解析 Windows .ini 文件的程序. POSIX 用户:创建一个解析 /etc/serves 文件的程序. 其它平台用户: 写一个解析特定结构的系统配置文件的程序.

 1 windows = {}
 2 with open(r'C:\Windows\win.ini') as f:
 3     # print(f.readlines())
 4     for line in f:
 5         if line.startswith(';'):
 6             continue
 7         if line.startswith('['):
 8             iterm = []
 9             name = line[1: line.rfind(']')]
10             windows.setdefault(name, iterm)
11             continue
12         if '=' in line:
13             windows[name].append(line.strip())
14 print(windows)

9–8. 模块研究. 提取模块的属性资料. 提示用户输入一个模块名(或者从命令行接受输入).然后使用 dir() 和其它内建函数提取模块的属性, 显示它们的名字, 类型, 值.

1 m = input('输入模块名: ')
2 module = __import__(m)
3 ml = dir(module)
4 # print(ml)
5 for i in ml:
6     print('name: ', i)
7     print('type: ', type(getattr(module,i)))
8     print('value: ', getattr(module,i))
9     print('')

9–9. Python 文档字符串. 

进入 Python 标准库所在的目录. 检查每个 .py 文件看是否有__doc__ 字符串, 如果有, 对其格式进行适当的整理归类. 你的程序执行完毕后, 应该会生成一个漂亮的清单. 里边列出哪些模块有文档字符串, 以及文档字符串的内容. 清单最后附上那些没有文档字符串模块的名字.附加题: 提取标准库中各模块内全部类(class)和函数的文档.

 1 import os
 2 
 3 pymodules = {}
 4 path = input("输入路径:")
 5 pyfiles = [f for f in os.listdir(os.path.abspath(path)) if f.endswith('.py')]
 6 
 7 for f in pyfiles:
 8     module = f[:-3]
 9     pymodules.setdefault(module, '')
10     pyfile = os.path.join(path, f) 
11     file = open(pyfile)
12     doc = False
13     for line in file:
14         if line.strip().startswith('"""') and line.strip().endswith('"""'):
15             pymodules[module] += line
16             file.close()
17             break
18         elif line.strip().startswith('"""') or line.strip().startswith('r"""') and len(line) > 3:
19             doc = True
20             pymodules[module] += line
21             continue
22         elif doc:
23             if line == '"""':
24                 pymodules[module] += line
25                 file.close()
26                 doc = False
27                 break
28             else:
29                 pymodules[module] += line
30         else:
31             continue
32     file.close()
33 
34 hasdoc = []
35 nodoc = []
36 for module in pymodules:
37     if pymodules[module]:
38         hasdoc.append(module)
39     else:
40         nodoc.append(module)
41 
42 print('没有文档模块:')
43 for key in nodoc:
44     print(key)
45 
46 print("")
47 
48 print("有文档模块:")
49 for key in hasdoc:
50     print("%s:%s" % key, pymodules[key])

9-10.家庭理财。创建一个家庭理财程序。你的程序需要处理储蓄 、支票、金融市场 ,定期存款等多
种账户。为每种账户提供一个菜单操作界面 ,要有存款、取款、借、贷等操作 。另外还要提 一个取消操作选项 。用户退出这个程序时相关数据应该保存到文件里去 (出于备份的目的, 序执行过程中也要备份)。

  1 # 函数思路不够用,只好用上类
  2 import os
  3 import json
  4 import sys
  5 
  6 class Fm:
  7 
  8     def deposit(self):
  9         """存款"""
 10         money = input("存款:")
 11         if money == 'q':
 12             self.saving()
 13         else:
 14             self.user_dict['余额'] += float(money)
 15             with open('%s.json' % self.ID, 'w') as f:
 16                 json.dump(self.user_dict, f)
 17             print("存款成功")
 18             self.saving()
 19 
 20     def withdrawal(self):
 21         """取款"""
 22         while True:
 23             money = input("取款:")
 24             if money == 'q':
 25                 self.saving()
 26             else:
 27                 if float(money) <= self.user_dict['余额']:
 28                     self.user_dict['余额'] -= float(money)
 29                     with open('%s.json' % self.ID, 'w') as f:
 30                         json.dump(self.user_dict, f)
 31                     print("取款成功")
 32                     self.saving()
 33                 else:
 34                     print("取款金额超出余额,重新输入")
 35 
 36     def loan(self):
 37         """借款"""
 38         money = input("存款:")
 39         if money == 'q':
 40             self.saving()
 41         else:
 42             self.user_dict['借款'] += float(money)
 43             with open('%s.json' % self.ID, 'w') as f:
 44                 json.dump(self.user_dict, f)
 45             print("借款成功")
 46             self.saving()
 47 
 48     def credit(self):
 49         """贷款"""
 50         money = input("贷款:")
 51         if money == 'q':
 52             self.saving()
 53         else:
 54             self.user_dict['贷款'] += float(money)
 55             with open('%s.json' % self.ID, 'w') as f:
 56                 json.dump(self.user_dict, f)
 57             print("贷款成功")
 58             self.saving()
 59 
 60     def saving(self):
 61         """储蓄主菜单"""
 62         showmenu = ("""
 63         [1]存款
 64         [2]取款
 65         [3]借款
 66         [4]贷款
 67         [5]返回
 68         [6]退出
 69         
 70         请输入编号:""")
 71         num = input(showmenu)
 72         if num == '6':
 73             sys.exit()
 74         elif num in '12345':
 75             if num == '1': self.deposit()
 76             if num == '2': self.withdrawal()
 77             if num == '3': self.loan()
 78             if num == '4': self.credit()
 79             if num == '5': self.main()
 80         else:
 81             print("输入有误")
 82 
 83     def main(self):
 84         """主菜单"""
 85         showmenu = ("""
 86         [1]储蓄
 87         [2]支票(未写)
 88         [3]金融市场(未写)
 89         [4]定期存款(未写)
 90         [5]退出
 91         
 92         请输入编号:""")
 93         num = input(showmenu)
 94         if num == '5':
 95             sys.exit()
 96         elif num in '1234':
 97             if num == '1': self.saving()
 98         else:
 99             print("输入有误")
100 
101     def registered(self):
102         """注册"""
103         while True:
104             ID = input('ID:')
105             filename = '%s.json' % ID
106             if filename in os.listdir(os.getcwd()):
107                 print("用户已存在")
108             else:
109                 passwd = input('密码:')
110                 name = input('姓名:')
111                 registered_user = {}
112                 registered_user['密码'] = passwd
113                 registered_user['姓名'] = name
114                 registered_user['余额'] = 0
115                 registered_user['借款'] = 0
116                 registered_user['贷款'] = 0
117                 filename = open('%s.json' % ID, 'w')
118                 json.dump(registered_user, filename)
119                 filename.close()
120                 print("注册成功")
121                 self.user()
122 
123     def login(self):
124         """登录"""
125         self.ID = input('ID:')
126         filename = '%s.json' % self.ID
127         if filename in os.listdir(os.getcwd()):
128             with open(filename) as user_file:
129                 self.user_dict = json.load(user_file)
130                 passwd = input("密码:")
131                 if self.user_dict['密码'] == passwd:
132                     print("登录成功")
133                     print("---------------\n"
134                           "姓名:{姓名}\n余额:{余额:.2f}\n借款:{借款:.2f}\n贷款:{贷款:.2f}\n"
135                           "---------------".format(**self.user_dict))
136                     self.main()
137                 else:
138                     print("密码错误")
139         else:
140             print("用户不存在")
141 
142     def user(self):
143         """账号"""
144         showmenu = ("""
145         [1]注册
146         [2]登录
147         [3]退出
148         
149         请输入编号:""")
150         num = input(showmenu)
151         while True:
152             if num == '3':
153                 break
154             elif num in '12':
155                 if num == '1': self.registered()
156                 if num == '2':
157                     if self.login():
158                         self.main()
159             else:
160                 print("输入有误")
161 
162 if __name__ == '__main__':
163     fm = Fm()
164     fm.user()

9–11. Web 站点地址.
a) 编写一个 URL 书签管理程序. 使用基于文本的菜单, 用户可以添加, 修改或者删除书签数据项. 书签数据项中包含站点的名称, URL 地址, 以及一行简单说明(可选). 另外提供检索功能,可以根据检索关键字在站点名称和 URL 两部分查找可能的匹配. 程序退出时把数据保存到一个磁盘文件中去; 再次执行时候加载保存的数据.
b)改进 a) 的解决方案, 把书签输出到一个合法且语法正确的 HTML 文件(.html 或 htm )中,这样用户就可以使用浏览器查看自己的书签清单. 另外提供创建”文件夹”功能, 对相关的书签进行分组管理.
附加题: 请阅读 Python 的 re 模块了解有关正则表达式的资料, 使用正则表达式对用户输入的 URL 进行验证.

  1 import sys
  2 import re
  3 
  4 regex = re.compile(r"^(((http|https)://)"  # http、https
  5                        r"?([a-z]{2,}))\." # www
  6                        r"([a-z0-9]+)\." #
  7                        r"([a-z]{3}|([a-z]{3}\.[a-z]{2,4}))$") #com、com.cn
  8 
  9 filename = "bookmark.txt"
 10 def add():
 11     """添加"""
 12     urllist = []
 13     while True:
 14         url = input("输入地址[b:返回]:").strip()
 15         if url == 'b':
 16             main()
 17         if regex.match(url):
 18             urlname = input("输入名称:").strip()
 19             description = input("简要说明:").strip()
 20             urllist.append(urlname)
 21             urllist.append(url)
 22             urllist.append(description)
 23             with open(filename, 'a+') as f:
 24                 f.write(str(urllist) + '\n')
 25                 print('添加成功')
 26         else:
 27             print("地址不规范")
 28 
 29 def modify():
 30     """修改"""
 31     urllist = []
 32     f = open(filename)
 33     for i, j in enumerate(f):
 34         urllist.append(eval(j))
 35         print(i, j, end='')
 36     f.close()
 37 
 38     while True:
 39         num = input("修改编号[b:返回]:")
 40         if num == 'b':
 41             main()
 42         if int(num) <= len(urllist):
 43             url = input("输入地址:").strip()
 44             if regex.match(url):
 45                 urlname = input("输入名称:").strip()
 46                 description = input("简要说明:").strip()
 47                 urllist[int(num)][0] = urlname
 48                 urllist[int(num)][1] = url
 49                 urllist[int(num)][2] = description
 50                 print("修改成功")
 51                 with open(filename, 'w') as urlfile:
 52                     for urlline in urllist:
 53                         urlfile.write(str(urlline) + '\n')
 54             else:
 55                 print("地址不规范")
 56         else:
 57             print('输入有误')
 58 
 59 
 60 def delete():
 61     """删除"""
 62     urllist = []
 63     f = open(filename)
 64     for i, j in enumerate(f):
 65         urllist.append(eval(j))
 66         print(i, j, end='')
 67     f.close()
 68 
 69     while True:
 70         num = input("\n删除编号[b:返回]:")
 71         if num == 'b':
 72             main()
 73         if int(num) <= len(urllist):
 74             del urllist[int(num)]
 75             print('删除成功')
 76             with open(filename, 'w') as urlfile:
 77                 for urlline in urllist:
 78                     urlfile.write(str(urlline) + '\n')
 79         else:
 80             print("输入有误")
 81 
 82 def find():
 83     """查找"""
 84     urllist = []
 85     while True:
 86         name = input("查找内容[b:返回]:")
 87         if name == 'b':
 88             main()
 89         with open(filename) as f:
 90             for urlline in f:
 91                 urllist.append(eval(urlline))
 92         if name in str(urllist):
 93             for urlline in urllist:
 94                 if name in urlline:
 95                     print('%s\n名称:%s\n地址:%s\n说明:%s\n%s' %
 96                           ('-'*20, urlline[0], urlline[1], urlline[2], '-'*20))
 97         else:
 98             print('书签不存在')
 99 
100 def main():
101     """主菜单"""
102     showmenu = ("""
103     [1]添加书签
104     [2]修改书签
105     [3]删除书签
106     [4]查找书签
107     [5]退出程序
108     
109     请输入编号:""")
110     num = input(showmenu)
111     if num == '5':
112         sys.exit()
113     elif num in '1234':
114         if num == '1': add()
115         if num == '2': modify()
116         if num == '3': delete()
117         if num == '4': find()
118     else:
119         print("输入有误")
120 
121 if __name__ == '__main__':
122     main()

9-12 用户名和密码。回顾练习7-5,修改代码使之可以支持“上次登录时间”。请参阅time模块中的文档了解如何记录用户上次登录的时间。另外提供一个系统管理员,他可以导出所有用户的用户名,密码(如需要可以加密),以及上次登录时间。
a)数据应保存在磁盘中,使用冒号:分隔,一次写入一行,例如“Joe:boohoo:953176591.145,文件中数据的行数应该等于你系统上的用户数。

b)进一步改进你的程序,不再一次写入一行,而使用pickle模块保存整个数据对象。请参阅pickle模块的文档了解如何序列化/扁平化对象,以及如何读写保存的对象。一般来说,这个解决方案的代码行数要比a)少;

c)使用shelve模块替换pickle模块,由于可以省去一些维护代码,这个解决方案的代码比b)的更少

  1 from datetime import datetime
  2 import hashlib, time, sys
  3 import pickle as p
  4 import shelve as s
  5 
  6 db = {}
  7 
  8 def newuser():
  9     """注册"""
 10     value = []
 11     prompt = 'login desired: '
 12     while True:
 13         name = input(prompt).lower()
 14         if not name.isalnum() and '' in name:
 15             print('name format error')
 16             continue
 17         else:
 18             if name in db:
 19                 prompt = 'name taken, try another: '
 20                 continue
 21             else:
 22                 break
 23     pwd = input('login password desired:')
 24     m = hashlib.md5()
 25     m.update(pwd.encode(encoding='utf-8'))
 26     value.append(m.hexdigest())
 27     value.append(datetime.now())
 28     value.append(time.time())
 29     db[name] = value
 30     print('new user is %s, register time is %s' % (name, db[name][1]))
 31 
 32 def olduser():
 33     """登录"""
 34     name = input('Username:').lower()
 35     pwd = input('Password:')
 36     m = hashlib.md5()
 37     m.update(pwd.encode(encoding='utf-8'))
 38     passwd = db.get(name)
 39     if passwd[0] == m.hexdigest():
 40         newtimestamp = time.time()
 41         newtime = datetime.now()
 42         if newtimestamp - db[name][2] < 14400:
 43             print('You already logged in at %s:' % db[name][1])
 44         else:
 45             passwd[1] = newtime
 46             print('Welcome back %s, login time is %s' % (name, passwd[1]))
 47     else:
 48         print('Login incorrect')
 49 
 50 def removeuser():
 51     """删除"""
 52     print(db)
 53     name = input('Input a user name to remove:').lower()
 54     if name in db:
 55         db.pop(name)
 56         print("Done")
 57     else:
 58         print('Input error')
 59 
 60 def getuser():
 61     """查询"""
 62     while True:
 63         name = input('login name desired:').lower()
 64         if not name.isalnum() and '' in name:
 65             print('name format error')
 66             continue
 67         else:
 68             if name not in db:
 69                 print('User name is not in db')
 70                 answer = input('register a new user? y/n').lower()
 71                 if 'y' == answer:
 72                     newuser()
 73                     break
 74                 elif 'n' == answer:
 75                     break
 76             else:
 77                 print('user name is already in db')
 78                 olduser()
 79                 break
 80 
 81 def textfile():
 82     """text"""
 83     print(db)
 84     f = open('account.txt', 'w')
 85     f.write(str(db))
 86     f.close()
 87 
 88 def picklefile():
 89     """pickle"""
 90     accountfile = 'pickle.data'
 91     f = open(accountfile, 'wb')
 92     p.dump(db, f)
 93     f.close()
 94 
 95     f = open(accountfile, 'rb')
 96     accountdb = p.load(f)
 97     print(accountdb)
 98 
 99 def shelvefile():
100     """shelve"""
101     accountfile = 'shelve.data'
102     accountdb = s.open(accountfile, 'c')
103     accountdb['data'] = db
104     accountdb.close()
105 
106     accountdb = s.open(accountfile, 'r')
107     print(accountdb['data'])
108 
109 def adminlogin():
110     """管理员"""
111     while True:
112         name = input('Username:').lower()
113         if not name.isalnum() and '' in name:
114             print('name format error')
115             continue
116         else:
117             pwd = input('Password:')
118             if name == 'root' and pwd == 'root':
119                 print('Welcom admin')
120                 if len(db) == 0:
121                     print('There is nothing you can do')
122                     showmenu()
123                 else:
124                     while True:
125                         answer = input('Output all account? y/n').lower()
126                         if 'y' == answer:
127                             prompt = "(T)ext\n(P)ickle\n(S)helve\n\nEnter choice:"
128                             choice = input(prompt).lower()
129                             if choice in 'tps':
130                                 if choice == 't': textfile()
131                                 if choice == 'p': picklefile()
132                                 if choice == 's': shelvefile()
133                         elif 'n' == answer:
134                             print('Bye')
135                             showmenu()
136                             sys.exit()
137             else:
138                 print('User name or password is wrong, input again')
139 
140 
141 def showmenu():
142     """功能"""
143     prompt = """
144     (N)ew User Login
145     (E)xisting User Login
146     (G)et user
147     (R)emove a existing user
148     (A)dmin Login
149     (Q)uit
150     
151     Enter choice: """
152 
153     done = False
154     while not done:
155         chosen = False
156         while not chosen:
157             try:
158                 choice = input(prompt).strip()[0].lower()
159             except (EOFError, KeyboardInterrupt):
160                 choice = 'q'
161             print('\nYou picked: [%s]' % choice)
162             if choice not in 'negraq':
163                 print('Invalid option, try again')
164             else:
165                 chosen = True
166 
167             if choice == 'q': done = True
168             if choice == 'n': newuser()
169             if choice == 'e': olduser()
170             if choice == 'g': getuser()
171             if choice == 'r': removeuser()
172             if choice == 'a': adminlogin()
173 
174 if __name__ == '__main__':
175     showmenu()

9-14 记录结果。修改你的计算器程序(练习5-6)使之接受命令行参数。例如$ calc.py 1 + 2 只输出计算结果。另外,把每个表达式和它的结果写入到一个磁盘文件中,当使用下面的命令时 $ calc.py print 会把记录的内容显示到屏幕上,然后重置文件。这里是样例展示:
$ calc.py 1 + 2

3

$ calc.py 3 ^ 3

27

$ calc.py print

1 + 2

3

3 ^ 3

27

$ calc.py print

 1 import sys, os
 2 
 3 if sys.argv[1] == 'print':
 4     if os.path.exists(r'test.txt'):
 5         f = open(r'test.txt', 'r')
 6         for line in f:
 7             print(line)
 8         f.close()
 9     else:
10         print('No file yet')
11     f = open(r'text.txt', 'w')
12     f.close()
13 else:
14     print(sys.argv[1], sys.argv[2], sys.argv[3])
15     a, b = sys.argv[1], sys.argv[3]
16     operation = sys.argv[2]
17     expression = sys.argv[1] + '' + sys.argv[2] + '' + sys.argv[3] + os.linesep
18     f = open(r'test.txt', 'a+')
19     f.write(expression)
20     if '+' == operation:
21         print(float(a) + float(b))
22         result = str(float(a) + float(b)) + os.linesep
23         f.write(result)
24     elif '-' == operation:
25         print(float(a) - float(b))
26         result = str(float(a) - float(b)) + os.linesep
27         f.write(result)
28     elif '**' == operation:
29         print(float(a) ** float(b))
30         result = str(float(a) ** float(b)) + os.linesep
31         f.write(result)
32     elif '/' == operation:
33         print(float(a) / float(b))
34         result = str(float(a) / float(b)) + os.linesep
35         f.write(result)
36     elif '%' == operation:
37         print(float(a) % float(b))
38         result = str(float(a) % float(b)) + os.linesep
39         f.write(result)
40     elif '*' == operation:
41         print(float(a) - float(b))
42         result = str(float(a) * float(b)) + os.linesep
43         f.write(result)
44     f.close()

9–15. 复制文件. 提示输入两个文件名(或者使用命令行参数). 把第一个文件的内容复制到第二个文件中去.

1 filename1 = input("输入文件名1:")
2 filename2 = input("输入文件名2:")
3 with open(filename1) as f:
4     filelines = f.readlines()
5 
6 with open(filename2, 'w') as f:
7     for fileline in filelines:
8         f.write(fileline)

9–16. 文本处理. 

人们输入的文字常常超过屏幕的最大宽度. 编写一个程序, 在一个文本文件中查找长度大于 80 个字符的文本行. 从最接近 80 个字符的单词断行, 把剩余文件插入到下一行处.程序执行完毕后, 应该没有超过 80 个字符的文本行了.

 1 filename = input("输入文件名:")
 2 f1 = open(filename)
 3 f = f1.readlines()
 4 f1.close()
 5 
 6 content = []
 7 for line in f:
 8     if len(line) > 80:
 9         num = list(line)
10         count = len(num) // 80
11         for i in range(count+1):
12             content.append("".join(num[:79]) + '\n')
13             num = num[79:]
14         content.append("".join(num))
15     else:
16         content.append(line)
17 
18 with open(filename, 'w') as f:
19     for fileline in content:
20         f.write(fileline)
21     print("Done")

9-17.文本处理 。创建一个原始的文本文件编辑器 。你的程序应该是菜单驱动的 ,有如下这些选项
1) 创建文件 (提示输入文件名和任意行的文本输入) :
2 ) 显示文件 (把文件的内容显示到屏幕):
3) 编辑文件 (提示输入要修改的行 ,然后让用户进行修改) :
4 ) 保存文件:
5 ) 退出。

 1 import sys
 2 import os
 3 
 4 def create():
 5     """创建文件"""
 6     filename = input('输入文件名[b:返回]:')
 7     if filename == 'b':
 8         main()
 9     while True:
10         text = input('输入内容[b:返回]:')
11         if text == 'b':
12             main()
13         with open(filename, 'a') as f:
14             f.write(text + '\n')
15         print("保存成功")
16 
17 def display():
18     """显示文件"""
19     while True:
20         filename = input('输入文件名[b:返回]:')
21         if filename == 'b':
22             main()
23         with open(filename) as f:
24             for num, line in enumerate(f, 1):
25                 print("第%d行:" % num, line, end='')
26         print('读取完毕')
27 
28 def edit():
29     """编辑文件"""
30     filename = input('输入文件名[b:返回]:')
31     if filename == 'b':
32         main()
33     filelist = []
34     f = open(filename)
35     for num, line in enumerate(f, 1):
36         filelist.append(line)
37         print("第%d行:" % num, line, end='')
38     f.close()
39     print('读取完毕')
40 
41     while True:
42         num = input("输入修改的行编号[b:返回]:")
43         if num == 'b':
44             main()
45         if int(num)-1 <= len(filelist):
46             text = input("输入内容:")
47             filelist[int(num)-1] = text + '\n'
48             with open(filename, 'w') as f:
49                 for line in filelist:
50                     f.write(line)
51         else:
52             print("输入有误")
53 
54 def save():
55     """保存文件"""
56     while True:
57         for_mat = input("查看文件格式(如: .txt)[b:返回]:")
58         if for_mat == 'b':
59             main()
60         if for_mat not in str(os.listdir(os.getcwd())):
61             print("格式不存在")
62         else:
63             for foldername, subfolders, filename in os.walk(os.getcwd()):
64                 print("已保存%s文件:\n%s" % (for_mat, '-' * 20))
65                 for file in filename:
66                     if file.endswith(for_mat):
67                         print(file)
68                 print("%s" % '-' * 20)
69 
70 def main():
71     showmenu = ("""
72     [1]创建文件
73     [2]显示文件
74     [3]编辑文件
75     [4]保存文件
76     [5]退出
77     
78     请输入编号:""")
79     while True:
80         num = input(showmenu)
81         if num == '5':
82             sys.exit()
83         elif num in '1234':
84             if num == '1': create()
85             if num == '2': display()
86             if num == '3': edit()
87             if num == '4': save()
88         else:
89             print("输入有误")
90 
91 if __name__ == '__main__':
92     main()

9–18. 搜索文件. 提示输入一个字节值(0 – 255)和一个文件名. 显示该字符在文件中出现的次数.

1 num = int(input("输入数字(0-255):"))
2 filename = input("输入文件名:")
3 with open(filename) as f:
4     print(sum(line.count(chr(num)) for line in f))

 9–20. 压缩文件. 

写一小段代码, 压缩/解压缩 gzip 或 bzip 格式的文件. 可以使用命令行下的 gzip 或 bzip2 以及 GUI 程序 PowerArchiver , StuffIt , 或 WinZip 来确认你的 Python支持这两个库.

 1 import gzip
 2 
 3 text = open(r'test.txt', 'rb')
 4 gzipfile = gzip.open(r'test.txt.gz', 'wb')
 5 gzipfile.writelines(text)
 6 text.close()
 7 gzipfile.close()
 8 
 9 gzipfile = gzip.open(r'test.txt.gz', 'rb')
10 text = open(r'test1.txt', 'wb')
11 content = gzipfile.read()
12 text.write(content)
13 gzipfile.close()
14 text.close()

9–21. ZIP 归档文件. 

创建一个程序, 可以往 ZIP 归档文件加入文件, 或从中提取文件,有可能的话, 加入创建ZIP 归档文件的功能.

 1 import zipfile, sys
 2 
 3 def archive_add():
 4     """归档、添加"""
 5     filename = input("压缩文件名[b:返回]:")
 6     if filename == 'b':
 7         main()
 8         sys.exit()
 9     while True:
10         file = input("文件名[b:返回]:")
11         if file == 'b':
12             archive_add()
13         filezip = zipfile.ZipFile(filename, 'a')
14         filezip.write(file)
15         filezip.close()
16         print('Done')
17 
18 def extract():
19     """提取"""
20     filename = input("压缩文件名[b:返回]:")
21     if filename == 'b':
22         main()
23         sys.exit()
24     filezip = zipfile.ZipFile(filename)
25     print(filezip.namelist())
26     filezip.close()
27     while True:
28         file = input("文件名[b:返回]:")
29         if file == 'b':
30             extract()
31         filezip = zipfile.ZipFile(filename)
32         filezip.extract(file)
33         filezip.close()
34         print('Done')
35 
36 def main():
37     menu = """
38     [1]归档、添加
39     [2]提取
40     [3]退出
41     
42     请输入编号:"""
43 
44     while True:
45         num = input(menu)
46         if num == '3':
47             break
48         elif num in '12':
49             if num == '1': archive_add()
50             if num == '2': extract()
51         else:
52             print('输入有误')
53 
54 if __name__ == '__main__':
55     main()

9–22. ZIP 归档文件. 
unzip -l 命令显示出的 ZIP 归档文件很无趣. 创建一个 Python脚本 lszip.py , 使它可以显示额外信息: 压缩文件大小, 每个文件的压缩比率(通过比较压缩前后文件大小), 以及完成的 time.ctime() 时间戳, 而不是只有日期和 HH:MM .
提示: 归档文件的 date_time 属性并不完整, 无法提供给 time.mktime() 使用….这由你自己决定.

 1 import zipfile, time, os
 2 
 3 filename = input("Zip file name:")
 4 print('Zip file size:%d bytes' % (os.stat(filename)).st_size)
 5 z = zipfile.ZipFile(filename)
 6 print('filename\t\t\tdatetime\t\t\tsize\tcompress size\trate')
 7 for info in z.infolist():
 8     t = time.ctime(time.mktime(tuple(list(info.date_time) + [0, 0, 0])))
 9     print('%8s\t%s\t%4d\t\t%4d\t\t%.2f%%' % (info.filename, t, info.file_size, info.compress_size,
10                                       float(info.compress_size / info.file_size * 100)  ))
11 z.close()

 9–23. TAR 归档文件. 
为 TAR 归档文件建立类似上个问题的程序. 这两种文件的不同之处在于 ZIP 文件通常是压缩的, 而 TAR 文件不是, 只是在 gzip 和 bzip2 的支持下才能完成压缩工作. 加入任意一种压缩格式支持.附加题: 同时支持 gzip 和 bzip2 .

 1 import tarfile, os
 2 
 3 def compressfile(tarname, filename1, filename2):
 4     t = tarfile.open(tarname, 'w:gz') #w.bz2
 5     t.add(filename1)
 6     t.add(filename2)
 7     t.close()
 8 
 9 def extractfile(tarname):
10     t = tarfile.open(tarname, 'r')
11     t.extractall(os.getcwd())
12     t.close()
13 
14 if __name__ == '__main__':
15     compressfile(r'abc.tar.gz', r'a.txt', r'b.txt')#r'abc.tar.bz2'
16     extractfile(r'abc.tar.gz')#r'abc.tar.bz2'

9–24. 归档文件转换. 

参考前两个问题的解决方案, 写一个程序, 在 ZIP (.zip) 和TAR/gzip (.tgz/.tar.gz) 或 TAR/bzip2 (.tbz/.tar.bz2) 归档文件间移动文件. 文件可能是已经存在的, 必要时请创建文件.

 1 import zipfile, tarfile, os
 2 
 3 def movefile(compressfile1, compressfile2, file):
 4 
 5     if compressfile1.endswith('.zip') and compressfile2.endswith(('.tar.gz', '.tgz', '.tbz', '.tar.bz2')):
 6         z = zipfile.ZipFile(compressfile1, 'a')
 7         if file not in z.namelist():
 8             f = open(file, 'w')
 9             f.close()
10             z.write(file)
11             z.extract(file)
12         else:
13             z.extract(file)
14         z.close()
15         t = tarfile.open(compressfile2)
16         ls = t.getnames()
17         if file not in ls:
18             t.extractall()
19             t.close()
20             mode = 'w:gz' if compressfile2.endswith(('tar.gz', 'tgz')) else 'w:bz2'
21             t = tarfile.open(compressfile2, mode)
22             for name in ls + [file]:
23                 t.add(name)
24             t.close()
25             os.remove(file)
26         t.close()
27 
28     elif compressfile1.endswith(('.tar.gz', '.tgz', '.tbz', '.tar.bz2')) and compressfile2.endswith('.zip'):
29         t = tarfile.open(compressfile1)
30         if file not in t.getnames():
31             f = open(file, 'w')
32             f.close()
33         else:
34             t.extract(file)
35         t.close()
36         z = zipfile.ZipFile(compressfile2, 'a')
37         if file not in z.namelist():
38             z.write(file)
39         z.close()
40         os.remove(file)
41 
42 if __name__ == '__main__':
43     compressfile1 = input('压缩文件名1:')
44     compressfile2 = input('压缩文件名2:')
45     file = input('文件名:')
46     movefile(compressfile1, compressfile2, file)

9–25. 通用解压程序.
创建一个程序, 接受任意数目的归档文件以及一个目标目录做为参数.归档文件格式可以是 .zip, .tgz, .tar.gz, .gz, .bz2, .tar.bz2, .tbz 中的一种或几种. 程序会把第一个归档文件解压后放入目标目录, 把其它归档文件解压后放入以对应文件名命名的目录下(不包括扩展名). 例如输入的文件名为 header.txt.gz 和 data.tgz , 目录为 incoming ,header.txt 会被解压到 incoming 而 data.tgz 中的文件会被放入 incoming/data .

 

 1 import zipfile, tarfile, gzip, bz2, os
 2 
 3 def extract(dir1, dir2):
 4     
 5     filelist = os.listdir(dir1)
 6     if filelist[0].endswith(('.tar.gz', '.tgz', '.tbz', '.tar.bz2')):
 7         t = tarfile.open(os.path.join(dir1, filelist[0]))
 8         t.extractall(dir2)
 9         t.close()
10 
11     elif filelist[0].endswith('.gz'):
12         g = gzip.open(os.path.join(dir1, filelist[0]), 'rb')
13         ug = open(os.path.join(dir2, os.path.splitext(filelist[0])[0]), 'wb')
14         data = g.read()
15         ug.write(data)
16         ug.close()
17         g.close()
18 
19     elif filelist[0].endswith('.bz2'):
20         b = bz2.BZ2File(os.path.join(dir1, filelist[0]))
21         ub = open(os.path.join(dir2, os.path.splitext(filelist[0])[0]), 'wb')
22         data = b.read()
23         ub.write(data)
24         ub.close()
25         b.close()
26 
27     elif filelist[0].endswith('.zip'):
28         z = zipfile.ZipFile(os.path.join(dir1, filelist[0]))
29         z.extractall(dir2)
30         z.close()
31         
32     filelist.remove(filelist[0])
33 
34     for file in filelist:
35         
36         dirname = os.path.splitext(file)[0]
37 
38         if dirname in os.listdir(dir2):
39             dirname = os.path.join(dir2, dirname, str(filelist.index(file)))
40         else:
41             dirname = os.path.join(dir2, dirname)
42         os.makedirs(dirname)
43 
44         if file.endswith(('.tar.gz', '.tgz', '.tbz', '.tar.bz2')):
45             t = tarfile.open(os.path.join(dir1, file))
46             t.extractall(dirname)
47             t.close()
48 
49         elif file.endswith('.gz'):
50             g = gzip.open(os.path.join(dir1, file), 'rb')
51             ug = open(os.path.join(dirname, os.path.splitext(file)[0]), 'wb')
52             data = g.read()
53             ug.write(data)
54             ug.close()
55             g.close()
56 
57         elif file.endswith('.bz2'):
58             b = bz2.BZ2File(os.path.join(dir1, file))
59             ub = open(os.path.join(dirname, os.path.splitext(file)[0]), 'wb')
60             data = b.read()
61             ub.write(data)
62             ub.close()
63             b.close()
64 
65         elif file.endswith('.zip'):
66             z = zipfile.ZipFile(os.path.join(dir1, file))
67             z.extractall(dirname)
68             z.close()
69 
70 if __name__ == '__main__':
71     dir1 = os.path.abspath(input('Path1: '))
72     dir2 = os.path.abspath(input('Path2: '))
73     extract(dir1, dir2)

 

点赞