python核心编程2 第9章 练习

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

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

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

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

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

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

9–4. 文件访问. 

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

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

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

filename = input("输入文件名:")
with open(filename) as f:
    for i in f:
        i = i.strip()
        if int(i) < 60:
            print("F")
        elif int(i) < 70:
            print("D")
        elif int(i) < 80:
            print("C")
        elif int(i) < 90:
            print("B")
        elif int(i) <= 100:
            print("A")
        else:
            print("%s不在范围" % i)

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

def file(filename1, filename2):
    with open(filename1) as f1:
        f1alllines = f1.readlines()

    with open(filename2) as f2:
        f2alllines = f2.readlines()

    minlen1 = min(len(f1alllines), len(f2alllines))
    for i in range(minlen1):
        if f1alllines[i] != f2alllines[i]:

            minlen2 = min(len(f1alllines[i]), len(f2alllines))
            for j in range(minlen2):
                if f1alllines[i][j] != f2alllines[i][j]:
                    return '不同行号: %s' % (i+1), '不同列号: %s' % (j+1)
    return '文件相同'

if __name__ == '__main__':
    filename1 = input("输入文件名1:")
    filename2 = input("输入文件名2:")
    print(file(filename1, filename2))

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

windows = {}
with open(r'C:\Windows\win.ini') as f:
    # print(f.readlines())
    for line in f:
        if line.startswith(';'):
            continue
        if line.startswith('['):
            iterm = []
            name = line[1: line.rfind(']')]
            windows.setdefault(name, iterm)
            continue
        if '=' in line:
            windows[name].append(line.strip())
print(windows)

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

m = input('输入模块名: ')
module = __import__(m)
ml = dir(module)
# print(ml)
for i in ml:
    print('name: ', i)
    print('type: ', type(getattr(module,i)))
    print('value: ', getattr(module,i))
    print('')

9–9. Python 文档字符串. 

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

import os

pymodules = {}
path = input("输入路径:")
pyfiles = [f for f in os.listdir(os.path.abspath(path)) if f.endswith('.py')]

for f in pyfiles:
    module = f[:-3]
    pymodules.setdefault(module, '')
    pyfile = os.path.join(path, f)
    file = open(pyfile)
    doc = False
    for line in file:
        if line.strip().startswith('"""') and line.strip().endswith('"""'):
            pymodules[module] += line
            file.close()
            break
        elif line.strip().startswith('"""') or line.strip().startswith('r"""') and len(line) > 3:
            doc = True
            pymodules[module] += line
            continue
        elif doc:
            if line == '"""':
                pymodules[module] += line
                file.close()
                doc = False
                break
            else:
                pymodules[module] += line
        else:
            continue
    file.close()

hasdoc = []
nodoc = []
for module in pymodules:
    if pymodules[module]:
        hasdoc.append(module)
    else:
        nodoc.append(module)

print('没有文档模块:')
for key in nodoc:
    print(key)

print("")

print("有文档模块:")
for key in hasdoc:
    print("%s:%s" % key, pymodules[key])

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

# 函数思路不够用,只好用上类
import os
import json
import sys

class Fm:

    def deposit(self):
        """存款"""
        money = input("存款:")
        if money == 'q':
            self.saving()
        else:
            self.user_dict['余额'] += float(money)
            with open('%s.json' % self.ID, 'w') as f:
                json.dump(self.user_dict, f)
            print("存款成功")
            self.saving()

    def withdrawal(self):
        """取款"""
        while True:
            money = input("取款:")
            if money == 'q':
                self.saving()
            else:
                if float(money) <= self.user_dict['余额']:
                    self.user_dict['余额'] -= float(money)
                    with open('%s.json' % self.ID, 'w') as f:
                        json.dump(self.user_dict, f)
                    print("取款成功")
                    self.saving()
                else:
                    print("取款金额超出余额,重新输入")

    def loan(self):
        """借款"""
        money = input("存款:")
        if money == 'q':
            self.saving()
        else:
            self.user_dict['借款'] += float(money)
            with open('%s.json' % self.ID, 'w') as f:
                json.dump(self.user_dict, f)
            print("借款成功")
            self.saving()

    def credit(self):
        """贷款"""
        money = input("贷款:")
        if money == 'q':
            self.saving()
        else:
            self.user_dict['贷款'] += float(money)
            with open('%s.json' % self.ID, 'w') as f:
                json.dump(self.user_dict, f)
            print("贷款成功")
            self.saving()

    def saving(self):
        """储蓄主菜单"""
        showmenu = ("""
        [1]存款
        [2]取款
        [3]借款
        [4]贷款
        [5]返回
        [6]退出
        
        请输入编号:""")
        num = input(showmenu)
        if num == '6':
            sys.exit()
        elif num in '12345':
            if num == '1': self.deposit()
            if num == '2': self.withdrawal()
            if num == '3': self.loan()
            if num == '4': self.credit()
            if num == '5': self.main()
        else:
            print("输入有误")

    def main(self):
        """主菜单"""
        showmenu = ("""
        [1]储蓄
        [2]支票(未写)
        [3]金融市场(未写)
        [4]定期存款(未写)
        [5]退出
        
        请输入编号:""")
        num = input(showmenu)
        if num == '5':
            sys.exit()
        elif num in '1234':
            if num == '1': self.saving()
        else:
            print("输入有误")

    def registered(self):
        """注册"""
        while True:
            ID = input('ID:')
            filename = '%s.json' % ID
            if filename in os.listdir(os.getcwd()):
                print("用户已存在")
            else:
                passwd = input('密码:')
                name = input('姓名:')
                registered_user = {}
                registered_user['密码'] = passwd
                registered_user['姓名'] = name
                registered_user['余额'] = 0
                registered_user['借款'] = 0
                registered_user['贷款'] = 0
                filename = open('%s.json' % ID, 'w')
                json.dump(registered_user, filename)
                filename.close()
                print("注册成功")
                self.user()

    def login(self):
        """登录"""
        self.ID = input('ID:')
        filename = '%s.json' % self.ID
        if filename in os.listdir(os.getcwd()):
            with open(filename) as user_file:
                self.user_dict = json.load(user_file)
                passwd = input("密码:")
                if self.user_dict['密码'] == passwd:
                    print("登录成功")
                    print("---------------\n"
                          "姓名:{姓名}\n余额:{余额:.2f}\n借款:{借款:.2f}\n贷款:{贷款:.2f}\n"
                          "---------------".format(**self.user_dict))
                    self.main()
                else:
                    print("密码错误")
        else:
            print("用户不存在")

    def user(self):
        """账号"""
        showmenu = ("""
        [1]注册
        [2]登录
        [3]退出
        
        请输入编号:""")
        num = input(showmenu)
        while True:
            if num == '3':
                break
            elif num in '12':
                if num == '1': self.registered()
                if num == '2':
                    if self.login():
                        self.main()
            else:
                print("输入有误")

if __name__ == '__main__':
    fm = Fm()
    fm.user()

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

import sys
import re

regex = re.compile(r"^(((http|https)://)"  # http、https
                       r"?([a-z]{2,}))\." # www
                       r"([a-z0-9]+)\." #
                       r"([a-z]{3}|([a-z]{3}\.[a-z]{2,4}))$") #com、com.cn

filename = "bookmark.txt"
def add():
    """添加"""
    urllist = []
    while True:
        url = input("输入地址[b:返回]:").strip()
        if url == 'b':
            main()
        if regex.match(url):
            urlname = input("输入名称:").strip()
            description = input("简要说明:").strip()
            urllist.append(urlname)
            urllist.append(url)
            urllist.append(description)
            with open(filename, 'a+') as f:
                f.write(str(urllist) + '\n')
                print('添加成功')
        else:
            print("地址不规范")

def modify():
    """修改"""
    urllist = []
    f = open(filename)
    for i, j in enumerate(f):
        urllist.append(eval(j))
        print(i, j, end='')
    f.close()

    while True:
        num = input("修改编号[b:返回]:")
        if num == 'b':
            main()
        if int(num) <= len(urllist):
            url = input("输入地址:").strip()
            if regex.match(url):
                urlname = input("输入名称:").strip()
                description = input("简要说明:").strip()
                urllist[int(num)][0] = urlname
                urllist[int(num)][1] = url
                urllist[int(num)][2] = description
                print("修改成功")
                with open(filename, 'w') as urlfile:
                    for urlline in urllist:
                        urlfile.write(str(urlline) + '\n')
            else:
                print("地址不规范")
        else:
            print('输入有误')


def delete():
    """删除"""
    urllist = []
    f = open(filename)
    for i, j in enumerate(f):
        urllist.append(eval(j))
        print(i, j, end='')
    f.close()

    while True:
        num = input("\n删除编号[b:返回]:")
        if num == 'b':
            main()
        if int(num) <= len(urllist):
            del urllist[int(num)]
            print('删除成功')
            with open(filename, 'w') as urlfile:
                for urlline in urllist:
                    urlfile.write(str(urlline) + '\n')
        else:
            print("输入有误")

def find():
    """查找"""
    urllist = []
    while True:
        name = input("查找内容[b:返回]:")
        if name == 'b':
            main()
        with open(filename) as f:
            for urlline in f:
                urllist.append(eval(urlline))
        if name in str(urllist):
            for urlline in urllist:
                if name in urlline:
                    print('%s\n名称:%s\n地址:%s\n说明:%s\n%s' %
                          ('-'*20, urlline[0], urlline[1], urlline[2], '-'*20))
        else:
            print('书签不存在')

def main():
    """主菜单"""
    showmenu = ("""
    [1]添加书签
    [2]修改书签
    [3]删除书签
    [4]查找书签
    [5]退出程序
    
    请输入编号:""")
    num = input(showmenu)
    if num == '5':
        sys.exit()
    elif num in '1234':
        if num == '1': add()
        if num == '2': modify()
        if num == '3': delete()
        if num == '4': find()
    else:
        print("输入有误")

if __name__ == '__main__':
    main()

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

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

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

from datetime import datetime
import hashlib, time, sys
import pickle as p
import shelve as s

db = {}

def newuser():
    """注册"""
    value = []
    prompt = 'login desired: '
    while True:
        name = input(prompt).lower()
        if not name.isalnum() and '' in name:
            print('name format error')
            continue
        else:
            if name in db:
                prompt = 'name taken, try another: '
                continue
            else:
                break
    pwd = input('login password desired:')
    m = hashlib.md5()
    m.update(pwd.encode(encoding='utf-8'))
    value.append(m.hexdigest())
    value.append(datetime.now())
    value.append(time.time())
    db[name] = value
    print('new user is %s, register time is %s' % (name, db[name][1]))

def olduser():
    """登录"""
    name = input('Username:').lower()
    pwd = input('Password:')
    m = hashlib.md5()
    m.update(pwd.encode(encoding='utf-8'))
    passwd = db.get(name)
    if passwd[0] == m.hexdigest():
        newtimestamp = time.time()
        newtime = datetime.now()
        if newtimestamp - db[name][2] < 14400:
            print('You already logged in at %s:' % db[name][1])
        else:
            passwd[1] = newtime
            print('Welcome back %s, login time is %s' % (name, passwd[1]))
    else:
        print('Login incorrect')

def removeuser():
    """删除"""
    print(db)
    name = input('Input a user name to remove:').lower()
    if name in db:
        db.pop(name)
        print("Done")
    else:
        print('Input error')

def getuser():
    """查询"""
    while True:
        name = input('login name desired:').lower()
        if not name.isalnum() and '' in name:
            print('name format error')
            continue
        else:
            if name not in db:
                print('User name is not in db')
                answer = input('register a new user? y/n').lower()
                if 'y' == answer:
                    newuser()
                    break
                elif 'n' == answer:
                    break
            else:
                print('user name is already in db')
                olduser()
                break

def textfile():
    """text"""
    print(db)
    f = open('account.txt', 'w')
    f.write(str(db))
    f.close()

def picklefile():
    """pickle"""
    accountfile = 'pickle.data'
    f = open(accountfile, 'wb')
    p.dump(db, f)
    f.close()

    f = open(accountfile, 'rb')
    accountdb = p.load(f)
    print(accountdb)

def shelvefile():
    """shelve"""
    accountfile = 'shelve.data'
    accountdb = s.open(accountfile, 'c')
    accountdb['data'] = db
    accountdb.close()

    accountdb = s.open(accountfile, 'r')
    print(accountdb['data'])

def adminlogin():
    """管理员"""
    while True:
        name = input('Username:').lower()
        if not name.isalnum() and '' in name:
            print('name format error')
            continue
        else:
            pwd = input('Password:')
            if name == 'root' and pwd == 'root':
                print('Welcom admin')
                if len(db) == 0:
                    print('There is nothing you can do')
                    showmenu()
                else:
                    while True:
                        answer = input('Output all account? y/n').lower()
                        if 'y' == answer:
                            prompt = "(T)ext\n(P)ickle\n(S)helve\n\nEnter choice:"
                            choice = input(prompt).lower()
                            if choice in 'tps':
                                if choice == 't': textfile()
                                if choice == 'p': picklefile()
                                if choice == 's': shelvefile()
                        elif 'n' == answer:
                            print('Bye')
                            showmenu()
                            sys.exit()
            else:
                print('User name or password is wrong, input again')


def showmenu():
    """功能"""
    prompt = """
    (N)ew User Login
    (E)xisting User Login
    (G)et user
    (R)emove a existing user
    (A)dmin Login
    (Q)uit
    
    Enter choice: """

    done = False
    while not done:
        chosen = False
        while not chosen:
            try:
                choice = input(prompt).strip()[0].lower()
            except (EOFError, KeyboardInterrupt):
                choice = 'q'
            print('\nYou picked: [%s]' % choice)
            if choice not in 'negraq':
                print('Invalid option, try again')
            else:
                chosen = True

            if choice == 'q': done = True
            if choice == 'n': newuser()
            if choice == 'e': olduser()
            if choice == 'g': getuser()
            if choice == 'r': removeuser()
            if choice == 'a': adminlogin()

if __name__ == '__main__':
    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

import sys, os

if sys.argv[1] == 'print':
    if os.path.exists(r'test.txt'):
        f = open(r'test.txt', 'r')
        for line in f:
            print(line)
        f.close()
    else:
        print('No file yet')
    f = open(r'text.txt', 'w')
    f.close()
else:
    print(sys.argv[1], sys.argv[2], sys.argv[3])
    a, b = sys.argv[1], sys.argv[3]
    operation = sys.argv[2]
    expression = sys.argv[1] + '' + sys.argv[2] + '' + sys.argv[3] + os.linesep
    f = open(r'test.txt', 'a+')
    f.write(expression)
    if '+' == operation:
        print(float(a) + float(b))
        result = str(float(a) + float(b)) + os.linesep
        f.write(result)
    elif '-' == operation:
        print(float(a) - float(b))
        result = str(float(a) - float(b)) + os.linesep
        f.write(result)
    elif '**' == operation:
        print(float(a) ** float(b))
        result = str(float(a) ** float(b)) + os.linesep
        f.write(result)
    elif '/' == operation:
        print(float(a) / float(b))
        result = str(float(a) / float(b)) + os.linesep
        f.write(result)
    elif '%' == operation:
        print(float(a) % float(b))
        result = str(float(a) % float(b)) + os.linesep
        f.write(result)
    elif '*' == operation:
        print(float(a) - float(b))
        result = str(float(a) * float(b)) + os.linesep
        f.write(result)
    f.close()

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

filename1 = input("输入文件名1:")
filename2 = input("输入文件名2:")
with open(filename1) as f:
    filelines = f.readlines()

with open(filename2, 'w') as f:
    for fileline in filelines:
        f.write(fileline)

9–16. 文本处理. 

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

filename = input("输入文件名:")
f1 = open(filename)
f = f1.readlines()
f1.close()

content = []
for line in f:
    if len(line) > 80:
        num = list(line)
        count = len(num) // 80
        for i in range(count+1):
            content.append("".join(num[:79]) + '\n')
            num = num[79:]
        content.append("".join(num))
    else:
        content.append(line)

with open(filename, 'w') as f:
    for fileline in content:
        f.write(fileline)
    print("Done")

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

import sys
import os

def create():
    """创建文件"""
    filename = input('输入文件名[b:返回]:')
    if filename == 'b':
        main()
    while True:
        text = input('输入内容[b:返回]:')
        if text == 'b':
            main()
        with open(filename, 'a') as f:
            f.write(text + '\n')
        print("保存成功")

def display():
    """显示文件"""
    while True:
        filename = input('输入文件名[b:返回]:')
        if filename == 'b':
            main()
        with open(filename) as f:
            for num, line in enumerate(f, 1):
                print("第%d行:" % num, line, end='')
        print('读取完毕')

def edit():
    """编辑文件"""
    filename = input('输入文件名[b:返回]:')
    if filename == 'b':
        main()
    filelist = []
    f = open(filename)
    for num, line in enumerate(f, 1):
        filelist.append(line)
        print("第%d行:" % num, line, end='')
    f.close()
    print('读取完毕')

    while True:
        num = input("输入修改的行编号[b:返回]:")
        if num == 'b':
            main()
        if int(num)-1 <= len(filelist):
            text = input("输入内容:")
            filelist[int(num)-1] = text + '\n'
            with open(filename, 'w') as f:
                for line in filelist:
                    f.write(line)
        else:
            print("输入有误")

def save():
    """保存文件"""
    while True:
        for_mat = input("查看文件格式(如: .txt)[b:返回]:")
        if for_mat == 'b':
            main()
        if for_mat not in str(os.listdir(os.getcwd())):
            print("格式不存在")
        else:
            for foldername, subfolders, filename in os.walk(os.getcwd()):
                print("已保存%s文件:\n%s" % (for_mat, '-' * 20))
                for file in filename:
                    if file.endswith(for_mat):
                        print(file)
                print("%s" % '-' * 20)

def main():
    showmenu = ("""
    [1]创建文件
    [2]显示文件
    [3]编辑文件
    [4]保存文件
    [5]退出
    
    请输入编号:""")
    while True:
        num = input(showmenu)
        if num == '5':
            sys.exit()
        elif num in '1234':
            if num == '1': create()
            if num == '2': display()
            if num == '3': edit()
            if num == '4': save()
        else:
            print("输入有误")

if __name__ == '__main__':
    main()

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

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

 9–20. 压缩文件. 

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

import gzip

text = open(r'test.txt', 'rb')
gzipfile = gzip.open(r'test.txt.gz', 'wb')
gzipfile.writelines(text)
text.close()
gzipfile.close()

gzipfile = gzip.open(r'test.txt.gz', 'rb')
text = open(r'test1.txt', 'wb')
content = gzipfile.read()
text.write(content)
gzipfile.close()
text.close()

 9–21. ZIP 归档文件. 

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

import zipfile, sys

def archive_add():
    """归档、添加"""
    filename = input("压缩文件名[b:返回]:")
    if filename == 'b':
        main()
        sys.exit()
    while True:
        file = input("文件名[b:返回]:")
        if file == 'b':
            archive_add()
        filezip = zipfile.ZipFile(filename, 'a')
        filezip.write(file)
        filezip.close()
        print('Done')

def extract():
    """提取"""
    filename = input("压缩文件名[b:返回]:")
    if filename == 'b':
        main()
        sys.exit()
    filezip = zipfile.ZipFile(filename)
    print(filezip.namelist())
    filezip.close()
    while True:
        file = input("文件名[b:返回]:")
        if file == 'b':
            extract()
        filezip = zipfile.ZipFile(filename)
        filezip.extract(file)
        filezip.close()
        print('Done')

def main():
    menu = """
    [1]归档、添加
    [2]提取
    [3]退出
    
    请输入编号:"""

    while True:
        num = input(menu)
        if num == '3':
            break
        elif num in '12':
            if num == '1': archive_add()
            if num == '2': extract()
        else:
            print('输入有误')

if __name__ == '__main__':
    main()

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

import zipfile, time, os

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

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

import tarfile, os

def compressfile(tarname, filename1, filename2):
    t = tarfile.open(tarname, 'w:gz') #w.bz2
    t.add(filename1)
    t.add(filename2)
    t.close()

def extractfile(tarname):
    t = tarfile.open(tarname, 'r')
    t.extractall(os.getcwd())
    t.close()

if __name__ == '__main__':
    compressfile(r'abc.tar.gz', r'a.txt', r'b.txt')#r'abc.tar.bz2'
    extractfile(r'abc.tar.gz')#r'abc.tar.bz2'

9–24. 归档文件转换. 

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

import zipfile, tarfile, os

def movefile(compressfile1, compressfile2, file):

    if compressfile1.endswith('.zip') and compressfile2.endswith(('.tar.gz', '.tgz', '.tbz', '.tar.bz2')):
        z = zipfile.ZipFile(compressfile1, 'a')
        if file not in z.namelist():
            f = open(file, 'w')
            f.close()
            z.write(file)
            z.extract(file)
        else:
            z.extract(file)
        z.close()
        t = tarfile.open(compressfile2)
        ls = t.getnames()
        if file not in ls:
            t.extractall()
            t.close()
            mode = 'w:gz' if compressfile2.endswith(('tar.gz', 'tgz')) else 'w:bz2'
            t = tarfile.open(compressfile2, mode)
            for name in ls + [file]:
                t.add(name)
            t.close()
            os.remove(file)
        t.close()
        
    elif compressfile1.endswith(('.tar.gz', '.tgz', '.tbz', '.tar.bz2')) and compressfile2.endswith('.zip'):
        t = tarfile.open(compressfile1)
        if file not in t.getnames():
            f = open(file, 'w')
            f.close()
        else:
            t.extract(file)
        t.close()
        z = zipfile.ZipFile(compressfile2, 'a')
        if file not in z.namelist():
            z.write(file)
        z.close()
        os.remove(file)

if __name__ == '__main__':
    compressfile1 = input('压缩文件名1:')
    compressfile2 = input('压缩文件名2:')
    file = input('文件名:')
    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 .
 

import zipfile, tarfile, gzip, bz2, os

def extract(dir1, dir2):
    
    filelist = os.listdir(dir1)
    if filelist[0].endswith(('.tar.gz', '.tgz', '.tbz', '.tar.bz2')):
        t = tarfile.open(os.path.join(dir1, filelist[0]))
        t.extractall(dir2)
        t.close()

    elif filelist[0].endswith('.gz'):
        g = gzip.open(os.path.join(dir1, filelist[0]), 'rb')
        ug = open(os.path.join(dir2, os.path.splitext(filelist[0])[0]), 'wb')
        data = g.read()
        ug.write(data)
        ug.close()
        g.close()

    elif filelist[0].endswith('.bz2'):
        b = bz2.BZ2File(os.path.join(dir1, filelist[0]))
        ub = open(os.path.join(dir2, os.path.splitext(filelist[0])[0]), 'wb')
        data = b.read()
        ub.write(data)
        ub.close()
        b.close()

    elif filelist[0].endswith('.zip'):
        z = zipfile.ZipFile(os.path.join(dir1, filelist[0]))
        z.extractall(dir2)
        z.close()
        
    filelist.remove(filelist[0])

    for file in filelist:
        
        dirname = os.path.splitext(file)[0]

        if dirname in os.listdir(dir2):
            dirname = os.path.join(dir2, dirname, str(filelist.index(file)))
        else:
            dirname = os.path.join(dir2, dirname)
        os.makedirs(dirname)

        if file.endswith(('.tar.gz', '.tgz', '.tbz', '.tar.bz2')):
            t = tarfile.open(os.path.join(dir1, file))
            t.extractall(dirname)
            t.close()

        elif file.endswith('.gz'):
            g = gzip.open(os.path.join(dir1, file), 'rb')
            ug = open(os.path.join(dirname, os.path.splitext(file)[0]), 'wb')
            data = g.read()
            ug.write(data)
            ug.close()
            g.close()

        elif file.endswith('.bz2'):
            b = bz2.BZ2File(os.path.join(dir1, file))
            ub = open(os.path.join(dirname, os.path.splitext(file)[0]), 'wb')
            data = b.read()
            ub.write(data)
            ub.close()
            b.close()

        elif file.endswith('.zip'):
            z = zipfile.ZipFile(os.path.join(dir1, file))
            z.extractall(dirname)
            z.close()

if __name__ == '__main__':
    dir1 = os.path.abspath(input('Path1: '))
    dir2 = os.path.abspath(input('Path2: '))
    extract(dir1, dir2)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值