/
Python Standard Library
翻译: Python 江湖群
2008-03-28 13:11:53
目录
[index.html 返回首页]
1. 文件格式
1.1. 概览
本章将描述用于处理不同文件格式的模块.
1.1.1. Markup 语言
Python 提供了一些用于处理可扩展标记语言( Extensible Markup Language , XML ) 和超文本标记语言( Hypertext Markup Language , HTML )的扩展. Python 同样提供了对 标准通用标记语言( Standard Generalized Markup Language , SGML )的支持.
所有这些格式都有着相同的结构, 因为 HTML 和 XML 都来自 SGML . 每个文档都是由 起始标签( start tags ), 结束标签( end tags ), 文本(又叫字符数据), 以及实体引用( entity references )构成:
This is a header This is the body text. The text can contain plain text ("character data"), tags, and entities.
在这个例子中, <document>, <header>, 以及 <body> 是起始标签. 每个起始标签都有一个对应的结束标签, 使用斜线 "/" 标记. 起始标签可以包含多个属性, 比如这里的 name 属性.
起始标签和它对应的结束标签中的任何东西被称为 元素( element ). 这里 document 元素包含 header 和 body 两个元素.
" 是一个字符实体( character entity ). 字符实体用于在文本区域中表示特殊的保留字符, 使用 & 指示. 这里它代表一个引号, 常见字符实体还有 "< ( < )" 和 " > ( > )" .
虽然 XML , HTML , SGML 使用相同的结构块, 但它们还有一些不同点. 在 XML 中, 所有元素必须有起始和结束标签, 所有标签必须正确嵌套( well-formed ). 而且 XML 是区分大小写的, 所以 <document> 和 <Document> 是不同的元素类型.
HTML 有很高灵活性, HTML 语法分析器一般会自动补全缺失标签; 例如, 当遇到一个以 <P> 标签开始的新段落, 却没有对应结束标签, 语法分析器会自动添加一个 </P>标签. HTML 也是区分大小写的. 另一方面, XML 允许你定义任何元素, 而 HTML 使用一些由 HTML 规范定义的固定元素.
SGML 有着更高的灵活性, 你可以使用自己的声明( declaration ) 定义源文件如何转换到元素结构, DTD ( document type description , 文件类型定义)可以用来 检查结构并补全缺失标签. 技术上来说, HTML 和 XML 都是 SGML 应用, 有各自的 SGML 声明, 而且 HTML 有一个标准 DTD .
Python 提供了多个 makeup 语言分析器. 由于 SGML 是最灵活的格式, Python 的 sgmllib 事实上很简单. 它不会去处理 DTD , 不过你可以继承它来提供更复杂的功能.
Python 的 HTML 支持基于 SGML 分析器. htmllib 将具体的格式输出工作交给 formatter 对象. formatter 模块包含一些标准格式化标志.
Python 的 XML 支持模块很复杂. 先前是只有与 sgmllib 类似的 xmllib , 后来加入了更高级的
-
expat 模块(可选). 而最新版本中已经准备废弃 xmllib ,启用 xml 包作为工具集.
1.1.2. 配置文件
ConfigParser 模块用于读取简单的配置文件, 类似 Windows 下的 INI 文件.
netrc 模块用于读取 .netrc 配置文件, shlex 模块用于读取类似 shell 脚本语法的配置文件.
1.1.3. 压缩档案格式
Python 的标准库提供了对 GZIP 和 ZIP ( 2.0 及以后) 格式的支持. 基于 zlib 模块, gzip 和 zipfile 模块分别用来处理这类文件.
1.2. xmllib 模块
xmllib 已在当前版本中申明不支持.
xmlib 模块提供了一个简单的 XML 语法分析器, 使用正则表达式将 XML 数据分离, 如 所示. 语法分析器只对文档做基本的检查, 例如是否只有一个顶层元素, 所有的标签是否匹配.
XML 数据一块一块地发送给 xmllib 分析器(例如在网路中传输的数据). 分析器在遇到起始标签, 数据区域, 结束标签, 和实体的时候调用不同的方法.
如果你只是对某些标签感兴趣, 你可以定义特殊的 start_tag 和 end_tag 方法, 这里 tag 是标签名称. 这些 start 函数使用它们对应标签的属性作为参数调用(传递时为一个字典).
1.2.0.1. Example 5-1. 使用 xmllib 模块获取元素的信息
File: xmllib-example-1.pyimport xmllibclass Parser(xmllib.XMLParser): # get quotation number def _ _init_ _(self, file=None): xmllib.XMLParser._ _init_ _(self) if file: self.load(file) def load(self, file): while 1: s = file.read(512) if not s: break self.feed(s) self.close() def start_quotation(self, attrs): print "id =>", attrs.get("id") raise EOFErrortry: c = Parser() c.load(open("samples/sample.xml"))except EOFError: pass*B*id => 031*b*
展示了一个简单(不完整)的内容输出引擎( rendering engine ). 分析器有一个元素堆栈( _ _tags ), 它连同文本片断传递给输出生成器. 生成器会在 style 字典中查询当前标签的层次, 如果不存在, 它将根据样式表创建一个新的样式描述.
1.2.0.2. Example 5-2. 使用 xmllib 模块
File: xmllib-example-2.pyimport xmllibimport string, sysSTYLESHEET = { # each element can contribute one or more style elements "quotation": {"style": "italic"}, "lang": {"weight": "bold"}, "name": {"weight": "medium"},}class Parser(xmllib.XMLParser): # a simple styling engine def _ _init_ _(self, renderer): xmllib.XMLParser._ _init_ _(self) self._ _data = [] self._ _tags = [] self._ _renderer = renderer def load(self, file): while 1: s = file.read(8192) if not s: break self.feed(s) self.close() def handle_data(self, data): self._ _data.append(data) def unknown_starttag(self, tag, attrs): if self._ _data: text = string.join(self._ _data, "") self._ _renderer.text(self._ _tags, text) self._ _tags.append(tag) self._ _data = [] def unknown_endtag(self, tag): self._ _tags.pop() if self._ _data: text = string.join(self._ _data, "") self._ _renderer.text(self._ _tags, text) self._ _data = []class DumbRenderer: def _ _init_ _(self): self.cache = {} def text(self, tags, text): # render text in the style given by the tag stack tags = tuple(tags) style = self.cache.get(tags) if style is None: # figure out a combined style style = {} for tag in tags: s = STYLESHEET.get(tag) if s: style.update(s) self.cache[tags] = style # update cache # write to standard output sys.stdout.write("%s =>\n" % style) sys.stdout.write(" " + repr(text) + "\n")## try it outr = DumbRenderer()c = Parser(r)c.load(open("samples/sample.xml"))*B*{'style': 'italic'} => 'I\'ve had a lot of developers come up to me and\012say, "I haven\'t had this much fun in a long time. It sure beats\012writing '{'style': 'italic', 'weight': 'bold'} => 'Cobol'{'style': 'italic'} => '" -- '{'style': 'italic', 'weight': 'medium'} => 'James Gosling'{'style': 'italic'} => ', on\012'{'weight': 'bold'} => 'Java'{'style': 'italic'} => '.'*b*
1.3. xml.parsers.expat 模块
(可选) xml.parsers.expat 模块是 James Clark's Expat XML parser 的接口. 展示了这个功能完整且性能很好的语法分析器.
1.3.0.1. Example 5-3. 使用 xml.parsers.expat 模块
File: xml-parsers-expat-example-1.pyfrom xml.parsers import expatclass Parser: def _ _init_ _(self): self._parser = expat.ParserCreate() self._parser.StartElementHandler = self.start self._parser.EndElementHandler = self.end self._parser.CharacterDataHandler = self.data def feed(self, data): self._parser.Parse(data, 0) def close(self): self._parser.Parse("", 1) # end of data del self._parser # get rid of circular references def start(self, tag, attrs): print "START", repr(tag), attrs def end(self, tag): print "END", repr(tag) def data(self, data): print "DATA", repr(data)p = Parser()p.feed("data ")p.close()*B*START u'tag' {}DATA u'data'END u'tag'*b*
注意即使你传入的是普通的文本, 这里的分析器仍然会返回 Unicode 字符串. 默认情况下, 分析器将源文本作为 UTF-8 解析. 如果要使用其他编码, 请确保 XML 文件包含 encoding 说明. 如 所示.
1.3.0.2. Example 5-4. 使用 xml.parsers.expat 模块读取 ISO Latin-1 文本
File: xml-parsers-expat-example-2.pyfrom xml.parsers import expatclass Parser: def _ _init_ _(self): self._parser = expat.ParserCreate() self._parser.StartElementHandler = self.start self._parser.EndElementHandler = self.end self._parser.CharacterDataHandler = self.data def feed(self, data): self._parser.Parse(data, 0) def close(self): self._parser.Parse("", 1) # end of data del self._parser # get rid of circular references def start(self, tag, attrs): print "START", repr(tag), attrs def end(self, tag): print "END", repr(tag) def data(self, data): print "DATA", repr(data)p = Parser()p.feed("""\""")p.close()*B*START u'author' {}DATA u'\012'START u'name' {}DATA u'fredrik lundh'END u'name'DATA u'\012'START u'city' {}DATA u'link\366ping'END u'city'DATA u'\012'END u'author'*b* fredrik lundh linköping
1.4. sgmllib 模块
sgmllib 模块, 提供了一个基本的 SGML 语法分析器. 它与 xmllib 分析器基本相同, 但限制更少(而且不是很完善). 如 所示.
和在 xmllib 中一样, 这个分析器在遇到起始标签, 数据区域, 结束标签以及实体时调用内部方法. 如果你只是对某些标签感兴趣, 那么你可以定义特殊的方法.
1.4.0.1. Example 5-5. 使用 sgmllib 模块提取 Title 元素
File: sgmllib-example-1.pyimport sgmllibimport stringclass FoundTitle(Exception): passclass ExtractTitle(sgmllib.SGMLParser): def _ _init_ _(self, verbose=0): sgmllib.SGMLParser._ _init_ _(self, verbose) self.title = self.data = None def handle_data(self, data): if self.data is not None: self.data.append(data) def start_title(self, attrs): self.data = [] def end_title(self): self.title = string.join(self.data, "") raise FoundTitle # abort parsing!def extract(file): # extract title from an HTML/SGML stream p = ExtractTitle() try: while 1: # read small chunks s = file.read(512) if not s: break p.feed(s) p.close() except FoundTitle: return p.title return None## try it outprint "html", "=>", extract(open("samples/sample.htm"))print "sgml", "=>", extract(open("samples/sample.sgm"))html => A Title.sgml => Quotations
重载 unknown_starttag 和 unknown_endtag 方法就可以处理所有的标签. 如 所示.
1.4.0.2. Example 5-6. 使用 sgmllib 模块格式化 SGML 文档
File: sgmllib-example-2.pyimport sgmllibimport cgi, sysclass PrettyPrinter(sgmllib.SGMLParser): # A simple SGML pretty printer def _ _init_ _(self): # initialize base class sgmllib.SGMLParser._ _init_ _(self) self.flag = 0 def newline(self): # force newline, if necessary if self.flag: sys.stdout.write("\n") self.flag = 0 def unknown_starttag(self, tag, attrs): # called for each start tag # the attrs argument is a list of (attr, value) # tuples. convert it to a string. text = "" for attr, value in attrs: text = text + " %s='%s'" % (attr, cgi.escape(value)) self.newline() sys.stdout.write("<%s%s>\n" % (tag, text)) def handle_data(self, text): # called for each text section sys.stdout.write(text) self.flag = (text[-1:] != "\n") def handle_entityref(self, text): # called for each entity sys.stdout.write("&%s;" % text) def unknown_endtag(self, tag): # called for each end tag self.newline() sys.stdout.write("<%s>" % tag)## try it outfile = open("samples/sample.sgm")p = PrettyPrinter()p.feed(file.read())p.close()*B*Quotations eff-bot, June 1997 Nobody expects the Spanish Inquisition! Amongstour weaponry are such diverse elements as fear, surprise,ruthless efficiency, and an almost fanatical devotion toGuido, and nice red uniforms — oh, damn!*b*
检查 SGML 文档是否是如 XML 那样 "正确格式化", 所有的元素是否正确嵌套, 起始和结束标签是否匹配等.
我们使用列表保存所有起始标签, 然后检查每个结束标签是否匹配前个起始标签. 最后确认到达文件末尾时没有未关闭的标签.
1.4.0.3. Example 5-7. 使用 sgmllib 模块检查格式
File: sgmllib-example-3.pyimport sgmllibclass WellFormednessChecker(sgmllib.SGMLParser): # check that an SGML document is 'well-formed' # (in the XML sense). def _ _init_ _(self, file=None): sgmllib.SGMLParser._ _init_ _(self) self.tags = [] if file: self.load(file) def load(self, file): while 1: s = file.read(8192) if not s: break self.feed(s) self.close() def close(self): sgmllib.SGMLParser.close(self) if self.tags: raise SyntaxError, "start tag %s not closed" % self.tags[-1] def unknown_starttag(self, start, attrs): self.tags.append(start) def unknown_endtag(self, end): start = self.tags.pop() if end != start: raise SyntaxError, "end tag %s does't match start tag %s" %\ (end, start)try: c = WellFormednessChecker() c.load(open("samples/sample.htm"))except SyntaxError: raise # report errorelse: print "document is well-formed"*B*Traceback (innermost last):...SyntaxError: end tag head does't match start tag meta*b*
最后, 中的类可以用来过滤 HTML 和 SGML 文档. 继承这个类, 然后实现 start 和 end 方法即可.
1.4.0.4. Example 5-8. 使用 sgmllib 模块过滤 SGML 文档
File: sgmllib-example-4.pyimport sgmllibimport cgi, string, sysclass SGMLFilter(sgmllib.SGMLParser): # sgml filter. override start/end to manipulate # document elements def _ _init_ _(self, outfile=None, infile=None): sgmllib.SGMLParser._ _init_ _(self) if not outfile: outfile = sys.stdout self.write = outfile.write if infile: self.load(infile) def load(self, file): while 1: s = file.read(8192) if not s: break self.feed(s) self.close() def handle_entityref(self, name): self.write("&%s;" % name) def handle_data(self, data): self.write(cgi.escape(data)) def unknown_starttag(self, tag, attrs): tag, attrs = self.start(tag, attrs) if tag: if not attrs: self.write("<%s>" % tag) else: self.write("<%s" % tag) for k, v in attrs: self.write(" %s=%s" % (k, repr(v))) self.write(">") def unknown_endtag(self, tag): tag = self.end(tag) if tag: self.write(" " % tag) def start(self, tag, attrs): return tag, attrs # override def end(self, tag): return tag # overrideclass Filter(SGMLFilter): def fixtag(self, tag): if tag == "em": tag = "i" if tag == "string": tag = "b" return string.upper(tag) def start(self, tag, attrs): return self.fixtag(tag), attrs def end(self, tag): return self.fixtag(tag)c = Filter()c.load(open("samples/sample.htm"))
1.5. htmllib 模块
htmlib 模块包含了一个标签驱动的( tag-driven ) HTML 语法分析器, 它会将数据发送至一个格式化对象. 如 所示. 更多关于如何解析 HTML 的例子请参阅 formatter 模块.
1.5.0.1. Example 5-9. 使用 htmllib 模块
File: htmllib-example-1.pyimport htmllibimport formatterimport stringclass Parser(htmllib.HTMLParser): # return a dictionary mapping anchor texts to lists # of associated hyperlinks def _ _init_ _(self, verbose=0): self.anchors = {} f = formatter.NullFormatter() htmllib.HTMLParser._ _init_ _(self, f, verbose) def anchor_bgn(self, href, name, type): self.save_bgn() self.anchor = href def anchor_end(self): text = string.strip(self.save_end()) if self.anchor and text: self.anchors[text] = self.anchors.get(text, []) + [self.anchor]file = open("samples/sample.htm")html = file.read()file.close()p = Parser()p.feed(html)p.close()for k, v in p.anchors.items(): print k, "=>", vprint*B*link => ['http://www.python.org']*b*
如果你只是想解析一个 HTML 文件, 而不是将它交给输出设备, 那么 sgmllib 模块会是更好的选择.
1.6. htmlentitydefs 模块
htmlentitydefs 模块包含一个由 HTML 中 ISO Latin-1 字符实体构成的字典. 如 所示.
1.6.0.1. Example 5-10. 使用 htmlentitydefs 模块
File: htmlentitydefs-example-1.pyimport htmlentitydefsentities = htmlentitydefs.entitydefsfor entity in "amp", "quot", "copy", "yen": print entity, "=", entities[entity]*B*amp = " = "copy = \302\251yen = \302\245*b*
Example 5-11 展示了如何将正则表达式与这个字典结合起来翻译字符串中的实体 ( cgi.escape 的逆向操作).
1.6.0.2. Example 5-11. 使用 htmlentitydefs 模块翻译实体
File: htmlentitydefs-example-2.pyimport htmlentitydefsimport reimport cgipattern = re.compile("&(\w+?);")def descape_entity(m, defs=htmlentitydefs.entitydefs): # callback: translate one entity to its ISO Latin value try: return defs[m.group(1)] except KeyError: return m.group(0) # use as isdef descape(string): return pattern.sub(descape_entity, string)print descape("<spam&eggs>")print descape(cgi.escape(""))*B* *b*
最后, 展示了如何将 XML 保留字符和 ISO Latin-1 字符转换为 XML 字符串. 与 cgi.escape 相似, 但它会替换非 ASCII 字符.
1.6.0.3. Example 5-12. 转义 ISO Latin-1 实体
File: htmlentitydefs-example-3.pyimport htmlentitydefsimport re, string# this pattern matches substrings of reserved and non-ASCII characterspattern = re.compile(r"[&<>\"\x80-\xff]+")# create character mapentity_map = {}for i in range(256): entity_map[chr(i)] = "&%d;" % ifor entity, char in htmlentitydefs.entitydefs.items(): if entity_map.has_key(char): entity_map[char] = "&%s;" % entitydef escape_entity(m, get=entity_map.get): return string.join(map(get, m.group()), "")def escape(string): return pattern.sub(escape_entity, string)print escape("")print escape("\303\245 i \303\245a \303\244 e \303\266")*B*<spam&eggs>å i åa ä e ö*b*
1.7. formatter 模块
formatter 模块提供了一些可用于 htmllib 的格式类( formatter classes ).
这些类有两种, formatter 和 writer . formatter 将 HTML 解析器的标签和数据流转换为适合输出设备的事件流( event stream ), 而 writer 将事件流输出到设备上. 如 所示.
大多情况下, 你可以使用 类进行格式化. 它会根据不同的格式化事件调用 writer 对象的方法. 类在每次方法调用时打印一条信息.
1.7.0.1. Example 5-13. 使用 formatter 模块将 HTML 转换为事件流
File: formatter-example-1.pyimport formatterimport htmllibw = formatter.AbstractWriter()f = formatter.AbstractFormatter(w)file = open("samples/sample.htm")p = htmllib.HTMLParser(f)p.feed(file.read())p.close()file.close()*B*send_paragraph(1)new_font(('h1', 0, 1, 0))send_flowing_data('A Chapter.')send_line_break()send_paragraph(1)new_font(None)send_flowing_data('Some text. Some more text. Some')send_flowing_data(' ')new_font((None, 1, None, None))send_flowing_data('emphasized')new_font(None)send_flowing_data(' text. A')send_flowing_data(' link')send_flowing_data('[1]')send_flowing_data('.')*b*
formatter 模块还提供了 类, 它会将任何传递给它的事件忽略; 以及 类, 它会将事件流转换为纯文本文档. 如 所示.
1.7.0.2. Example 5-14. 使用 formatter 模块将 HTML 转换为纯文本
File: formatter-example-2.pyimport formatterimport htmllibw = formatter.DumbWriter() # plain textf = formatter.AbstractFormatter(w)file = open("samples/sample.htm")# print html body as plain textp = htmllib.HTMLParser(f)p.feed(file.read())p.close()file.close()# print linksprintprinti = 1for link in p.anchorlist: print i, "=>", link i = i + 1*B*A Chapter.Some text. Some more text. Some emphasized text. A link[1].1 => http://www.python.org*b*
提供了一个自定义的 Writer , 它继承自 类, 会记录当前字体样式并根据字体美化输出格式.
1.7.0.3. Example 5-15. 使用 formatter 模块自定义 Writer
File: formatter-example-3.pyimport formatterimport htmllib, stringclass Writer(formatter.DumbWriter): def _ _init_ _(self): formatter.DumbWriter._ _init_ _(self) self.tag = "" self.bold = self.italic = 0 self.fonts = [] def new_font(self, font): if font is None: font = self.fonts.pop() self.tag, self.bold, self.italic = font else: self.fonts.append((self.tag, self.bold, self.italic)) tag, bold, italic, typewriter = font if tag is not None: self.tag = tag if bold is not None: self.bold = bold if italic is not None: self.italic = italic def send_flowing_data(self, data): if not data: return atbreak = self.atbreak or data[0] in string.whitespace for word in string.split(data): if atbreak: self.file.write(" ") if self.tag in ("h1", "h2", "h3"): word = string.upper(word) if self.bold: word = "*" + word + "*" if self.italic: word = "_" + word + "_" self.file.write(word) atbreak = 1 self.atbreak = data[-1] in string.whitespacew = Writer()f = formatter.AbstractFormatter(w)file = open("samples/sample.htm")# print html body as plain textp = htmllib.HTMLParser(f)p.feed(file.read())p.close()*B*_A_ _CHAPTER._Some text. Some more text. Some *emphasized* text. A link[1].*b*
1.8. ConfigParser 模块
ConfigParser 模块用于读取配置文件.
配置文件的格式与 Windows INI 文件类似, 可以包含一个或多个区域( section ), 每个区域可以有多个配置条目.
这里有个样例配置文件, 在 用到了这个文件:
[book]title: The Python Standard Libraryauthor: Fredrik Lundhemail: fredrik@pythonware.comversion: 2.0-001115[ematter]pages: 250[hardcopy]pages: 350
使用 ConfigParser 模块读取这个配制文件.
1.8.0.1. Example 5-16. 使用 ConfigParser 模块
File: configparser-example-1.pyimport ConfigParserimport stringconfig = ConfigParser.ConfigParser()config.read("samples/sample.ini")# print summaryprintprint string.upper(config.get("book", "title"))print "by", config.get("book", "author"),print "(" + config.get("book", "email") + ")"printprint config.get("ematter", "pages"), "pages"print# dump entire config filefor section in config.sections(): print section for option in config.options(section): print " ", option, "=", config.get(section, option)*B*THE PYTHON STANDARD LIBRARYby Fredrik Lundh (fredrik@pythonware.com)250 pagesbook title = The Python Standard Library email = fredrik@pythonware.com author = Fredrik Lundh version = 2.0-001115 _ _name_ _ = bookematter _ _name_ _ = ematter pages = 250hardcopy _ _name_ _ = hardcopy pages = 350*b*
Python 2.0 以后, ConfigParser 模块也可以将配置数据写入文件, 如 所示.
1.8.0.2. Example 5-17. 使用 ConfigParser 模块写入配置数据
File: configparser-example-2.pyimport ConfigParserimport sysconfig = ConfigParser.ConfigParser()# set a number of parametersconfig.add_section("book")config.set("book", "title", "the python standard library")config.set("book", "author", "fredrik lundh")config.add_section("ematter")config.set("ematter", "pages", 250)# write to screenconfig.write(sys.stdout)*B*[book]title = the python standard libraryauthor = fredrik lundh[ematter]pages = 250*b*
1.9. netrc 模块
netrc 模块可以用来解析 .netrc 配置文件, 如 Example 5-18 所示. 该文件用于在用户的 home 目录储存 FTP 用户名和密码. (别忘记设置这个文件的属性为: "chmod 0600 ~/.netrc," 这样只有当前用户能访问).
1.9.0.1. Example 5-18. 使用 netrc 模块
File: netrc-example-1.pyimport netrc# default is $HOME/.netrcinfo = netrc.netrc("samples/sample.netrc")login, account, password = info.authenticators("secret.fbi")print "login", "=>", repr(login)print "account", "=>", repr(account)print "password", "=>", repr(password)*B*login => 'mulder'account => Nonepassword => 'trustno1'*b*
1.10. shlex 模块
shlex 模块为基于 Unix shell 语法的语言提供了一个简单的 lexer (也就是 tokenizer). 如 所示.
1.10.0.1. Example 5-19. 使用 shlex 模块
File: shlex-example-1.pyimport shlexlexer = shlex.shlex(open("samples/sample.netrc", "r"))lexer.wordchars = lexer.wordchars + "._"while 1: token = lexer.get_token() if not token: break print repr(token)*B*'machine''secret.fbi''login''mulder''password''trustno1''machine''non.secret.fbi''login''scully''password''noway'*b*
1.11. zipfile 模块
( 2.0 新增) zipfile 模块可以用来读写 ZIP 格式.
1.11.1. 列出内容
使用 namelist 和 infolist 方法可以列出压缩档的内容, 前者返回由文件名组成的列表, 后者返回由 实例组成的列表. 如 所示.
1.11.1.1. Example 5-20. 使用 zipfile 模块列出 ZIP 文档中的文件
File: zipfile-example-1.pyimport zipfilefile = zipfile.ZipFile("samples/sample.zip", "r")# list filenamesfor name in file.namelist(): print name,print# list file informationfor info in file.infolist(): print info.filename, info.date_time, info.file_size*B*sample.txt sample.jpgsample.txt (1999, 9, 11, 20, 11, 8) 302sample.jpg (1999, 9, 18, 16, 9, 44) 4762*b*
1.11.2. 从 ZIP 文件中读取数据
调用 read 方法就可以从 ZIP 文档中读取数据. 它接受一个文件名作为参数, 返回字符串. 如 所示.
1.11.2.1. Example 5-21. 使用 zipfile 模块从 ZIP 文件中读取数据
File: zipfile-example-2.pyimport zipfilefile = zipfile.ZipFile("samples/sample.zip", "r")for name in file.namelist(): data = file.read(name) print name, len(data), repr(data[:10])*B*sample.txt 302 'We will pe'sample.jpg 4762 '\377\330\377\340\000\020JFIF'*b*
1.11.3. 向 ZIP 文件写入数据
向压缩档加入文件很简单, 将文件名, 文件在 ZIP 档中的名称传递给 write 方法即可.
将 samples 目录中的所有文件打包为一个 ZIP 文件.
1.11.3.1. Example 5-22. 使用 zipfile 模块将文件储存在 ZIP 文件里
File: zipfile-example-3.pyimport zipfileimport glob, os# open the zip file for writing, and write stuff to itfile = zipfile.ZipFile("test.zip", "w")for name in glob.glob("samples/*"): file.write(name, os.path.basename(name), zipfile.ZIP_DEFLATED)file.close()# open the file again, to see what's in itfile = zipfile.ZipFile("test.zip", "r")for info in file.infolist(): print info.filename, info.date_time, info.file_size, info.compress_size*B*sample.wav (1999, 8, 15, 21, 26, 46) 13260 10985sample.jpg (1999, 9, 18, 16, 9, 44) 4762 4626sample.au (1999, 7, 18, 20, 57, 34) 1676 1103...*b*
write 方法的第三个可选参数用于控制是否使用压缩. 默认为 zipfile.ZIP_STORED , 意味着只是将数据储存在档案里而不进行任何压缩. 如果安装了 zlib 模块, 那么就可以使用 zipfile.ZIP_DEFLATED 进行压缩.
zipfile 模块也可以向档案中添加字符串. 不过, 这需要一点技巧, 你需要创建一个 实例, 并正确配置它. 提供了一种简单的解决办法.
1.11.3.2. Example 5-23. 使用 zipfile 模块在 ZIP 文件中储存字符串
File: zipfile-example-4.pyimport zipfileimport glob, os, timefile = zipfile.ZipFile("test.zip", "w")now = time.localtime(time.time())[:6]for name in ("life", "of", "brian"): info = zipfile.ZipInfo(name) info.date_time = now info.compress_type = zipfile.ZIP_DEFLATED file.writestr(info, name*1000)file.close()# open the file again, to see what's in itfile = zipfile.ZipFile("test.zip", "r")for info in file.infolist(): print info.filename, info.date_time, info.file_size, info.compress_size*B*life (2000, 12, 1, 0, 12, 1) 4000 26of (2000, 12, 1, 0, 12, 1) 2000 18brian (2000, 12, 1, 0, 12, 1) 5000 31*b*
1.12. gzip 模块
gzip 模块用来读写 gzip 格式的压缩文件, 如 所示.
1.12.0.1. Example 5-24. 使用 gzip 模块读取压缩文件
File: gzip-example-1.pyimport gzipfile = gzip.GzipFile("samples/sample.gz")print file.read()*B*Well it certainly looks as though we're in fora splendid afternoon's sport in this the 127thUpperclass Twit of the Year Show.*b*
标准的实现并不支持 seek 和 tell 方法. 不过 可以解决这个问题.
1.12.0.2. Example 5-25. 给 gzip 模块添加 seek/tell 支持
File: gzip-example-2.pyimport gzipclass gzipFile(gzip.GzipFile): # adds seek/tell support to GzipFile offset = 0 def read(self, size=None): data = gzip.GzipFile.read(self, size) self.offset = self.offset + len(data) return data def seek(self, offset, whence=0): # figure out new position (we can only seek forwards) if whence == 0: position = offset elif whence == 1: position = self.offset + offset else: raise IOError, "Illegal argument" if position < self.offset: raise IOError, "Cannot seek backwards" # skip forward, in 16k blocks while position > self.offset: if not self.read(min(position - self.offset, 16384)): break def tell(self): return self.offset## try itfile = gzipFile("samples/sample.gz")file.seek(80)print file.read()*B*this the 127thUpperclass Twit of the Year Show.*b*
PythonStandardLib/chpt5 (2009-12-25 07:15:18由localhost编辑)
- Page.execute = 0.450s
- getACL = 0.132s
- init = 0.002s
- load_multi_cfg = 0.000s
- run = 1.038s
- send_page = 0.993s
- send_page_content = 0.458s
- send_page_content|1 = 0.164s
- send_page|1 = 0.198s
- total = 1.040s