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)