返回介绍

实际应用中的文件

发布于 2024-01-29 22:24:16 字数 6295 浏览 0 评论 0 收藏 0

让我们看一个能够说明文件处理原理的简单例子。首先为输出而打开一个新文件,写入一个字符串(以行终止符\n结束),之后关闭文件。接下来,我们将会在输入模式下再一次打开同一文件,读取该行。注意第二个readline调用返回一个空字符串。这是Python文件方法告诉我们已经到达文件底部(文件的空行是含有新行符的字符串,而不是空字符串)。以下是完整的交互模式会话:

注意,文件write调用返回了在Python 3.0中写入的字符数;在Python 2.6中,它们不会,因此,你不会看到交互地响应这些数字。这个例子把一行文本写成字符串,包括行终止符\n。写入方法不会为我们添加行终止符,所以程序必须包含它来严格地终止行(否则,下次写入时会简单地延长文件的当前行)。

如果想要显示带有末行字符解释的文件内容,用文件对象的read方法把整个文件读入到一个字符串中,并打印它:

如果想要一行一行地扫描一个文本文件,文件迭代器往往是最佳选择:

以这种方式编码的时候,open临时创建的文件对象将自动在每次循环迭代的时候读入并返回一行。这种形式通常很容易编写,对于内存使用很好,并且比其他选项更快(当然,根据有多少变量)。由于我们还没有介绍语句或迭代器,你将必须等到第14章才能完全理解这段代码。

Python 3.0中的文本和二进制文件

严格地讲,前面小节中的示例使用了文本文件。在Python 3.0和Python 2.6中,文件类型都由open的第二个参数决定,模式字符串包含一个"b"表示二进制。Python总是支持文本和二进制文件,但是在Python 3.0中,二者之间有明显的区别:

·文本文件把内容表示为常规的str字符串,自动执行Unicode编码和解码,并且默认执行末行转换。

·二进制文件把内容表示为一个特殊的bytes字符串类型,并且允许程序不修改地访问文件内容。

相反,Python 2.6文本文件处理8位文本和二进制数据,并且有一种特殊的字符串类型和文件接口(unicode字符串和odecs.open)来处理Unicode文本。Python 3.0中的区别源自于简单文本和Unicode文本都合并为一种常规字符串类型这一事实——这是有意义的,因为所有的文本都是Unicode,包括ASCII和其他的8位编码。

由于大多数程序员只是处理ASCII文本,他们可以用前面的示例中所使用的基本文本文件接口和常规的字符串来做到。在Python 3.0中,所有的字符串从技术上讲都是Unicode,但是ASCII用户通常不会留意。实际上,如果你的脚本仅限于处理如此简单形式的文本的话,文件和字符串在Python 3.0和Python 2.6中同样地工作。

如果需要处理国际化应用程序或者面向字节的数据,Python 3.0中的区别会影响到代码(通常是更好的影响)。通常,你必须使用bytes字符串处理二进制文件,并且用常规的str字符串处理文本文件。此外,由于文本文件实现了Unicode编码,不能以文本模式打开一个二进制数据文件——将其内容解码为Unicode文本可能会失败。

让我们来看一个示例。当你读取一个二进制数据文件的时候,得到了一个bytes对象——表示绝对字节值的较小整数的一个序列(可能会也可能不会对应为字符),其外观几乎与常规的字符串完全相同:

此外,二进制文件不会对数据执行任何末行转换;在根据转化写入和读取并实现Unicode编码的时候,文本文件默认地把所有形式和\n之间映射起来。由于Unicode和二进制数据对很多Python程序员来说并不直接相关,我们推迟到第36章再完整地介绍。现在,让我们继续看一些更为实际的文件示例。

在文件中存储并解析Python对象

现在,让我们创建一个较大的文件。下面这个例子将把多种Python对象占用多行写入文本文件。需要注意的是,我们必须使用转换工具把对象转成字符串。注意文件数据在脚本中一定是字符串,而写入方法不会自动地替我们做任何向字符串格式转换的工作(对于空格,在这里我将从写方法中忽视字节计数返回值)。

一旦我们创建了文件就可以通过打开和读取字符串来查看文件的内容(单步操作)。注意:交互模式的回显给出了正确的字节内容,而print语句则会解释内嵌行终止符来给予用户满意的结果:

现在我们不得不使用其他转换工具,把文本文件中的字符串转换成真正的Python对象。鉴于Python不会自动把字符串转换为数字或其他类型的对象,如果我们需要使用诸如索引、加法等普通对象工具,就得这么做。

对第一行来说,我们使用字符串rstrip方法去掉多余的行终止符;line[:-1]分片也可以,但是只有确定所有行都含有"\n"的时候才行(文件中最后一行有时候会没有)。

到目前为止,我们读取了包含字符串的行。现在,让我们读取包含数字的下一行,并解析出(抽取出)该行中的对象:

我们这里使用字符串split方法,从逗号分隔符的地方将整行断开,得到的结果就是含有个别数字的子字符串列表。如果我们想对这些数字做数学运算还是得把字符串转换为整数:

int能够把数字字符串转换为整数对象,我们在第4章所介绍的列表解析表达式也可以一次性对列表中的每个项使用调用(你可以在本书稍后的地方找到更多关于列表解析的介绍)。注意:我们不一定非要运行rstrip来删除最后部分的"\n",int和一些其他转换方法会忽略数字旁边的空白。

最后,要转换文件第三行所储存的列表和字典,我们可以运行eval这一内置函数,eval能够把字符串当作可执行程序代码(从技术上来讲,就是一个含有Python表达式的字符串)。

因为所有这些解析和转换的最终结果是一个普通的Python对象列表,而不是字符串。现在我们可以在脚本内应用列表和字典操作了。

用pickle存储Python的原生对象

如前面程序所示,使用eval可以把字符串转换成对象,它是一个功能强大的工具。事实上,它有时太过于强大。eval会高高兴兴地执行Python的任何表达式,甚至是有可能会删除计算机上所有文件的表达式,只要给予必要的权限。如果你真的想储存Python原生对象,但又无法信赖文件的数据来源,Python标准库pickle模块会是个理想的选择。

pickle模块是能够让我们直接在文件中存储几乎任何Python对象的高级工具,也并不要求我们把字符串转换来转换去。它就像是超级通用的数据格式化和解析工具。例如,想要在文件中储存字典,就直接用pickle来储存。

之后,将来想要取回字典时,只要简单地再用一次pickle进行重建就可以了:

我们取回等价的字典对象,没有手动断开或转换的要求。pickle模块执行所谓的对象序列化(object serialization),也就是对象和字节字符串之间的相互转换。但我们要做的工作却很少。事实上,pickle内部将字典转成字符串形式,不过这其实没什么可看的(如果我们在其他模式下使用pickle会更难):

因为pickle能够依靠这一格式重建对象,我们不必自己手动来处理。有关pickle模块的更多内容可以参考Python标准库手册,或者在交互模式下输入pickle传给help来查阅相关信息。与此同时你也可以顺便看一看shelve模块。shelve用pickle把Python对象存放到按键访问的文件系统中,不过这并不在我们讨论的范围之内(尽管你可以在本书第27章看到应用shelve的一个示例,并且在第30章和第36章看到其他的pickle示例)。

注意:我们以二进制模式打开用来存储pickle化的对象的文件,二进制模式总是Python 3.0中必需的,因为pickle程序创建和使用一个bytes字符串对象,并且这些对象意味着二进制模式文件(文本模式文件意味着Python 3.0中的str字符串)。在早期的Python中,对于协议0使用文本模式文件是没有问题的(默认情况下,它创建ASCII文本),只要一致地使用文本模式;较高的协议要求二进制模式文件。Python 3.0的默认协议是3(二进制),但是,它即便对于协议0也创建bytes。参见第36章Python的库手册或其他参考书来了解关于这一点的更多细节。

Python 2.6也有一个cPickle模块,它是pickle的一个优化版本,可以直接导入以提高速度。Python 3.0把这模块改名为_pickle,并且在pickle中自动使用它——脚本直接导入pickle并且允许Python优化它。

文件中打包二进制数据的存储与解析

在我们继续学习下面的内容之前,还有一个和文件相关的细节需要注意:有些高级应用程序也需要处理打包的二进制数据,这些数据可能是C语言程序生成的。Python的标准库中包含一个能够在这一范围起作用的工具:struct模块能够构造并解析打包的二进制数据。从某种意义上说,它是另一个数据转换工具,它能够把文件中的字符串解读为二进制数据。

例如,要生成一个打包的二进制数据文件,用'wb'(写入二进制)模式打开它,并将一个格式化字符串和几个Python对象传给struct。这里用的格式化字符串是指一个4字节整数、一个包含4个字符的字符串以及一个2位整数的数据包,所有这些都按照高位在前(big-endian)的形式(其他格式代码能够处理补位字节、浮点数等)。

Python生成一个我们通常写入文件的二进制数据字符串(主要由不可打印的字符组成,这些字符以十六进制转义的格式进行打印)。要将值解析为普通Python的对象,可以简单地读取字符串,并使用相同格式的字符串把它解压出来就可以了。Python能够把值提取出来转换为普通的Python对象(整数和字符串)。

二进制数据文件是高级而又有点低层次的工具,我们在这不再讲更多的细节了。如果需要更多帮助,可以参考Python库手册或者在交互模式下将struct传给help函数查阅相关的信息。同时需要注意的是,一般来说,二进制文件处理模式'wb'和'rb'可用于处理更简单的二进制文件。例如,图片或音频文件是不需要解压它的内容的。

文件上下文管理器

我们还要看看第33章对于文件的上下文管理器支持的讨论,在Python 3.0和Python 2.6中有所更新。因而比文件自身多了一个异常处理功能,它允许我们把文件处理代码包装到一个逻辑层中,以确保在退出后可以自动关闭文件,而不是依赖于垃圾收集上的自动关闭:

我们在第33章看到过的try/finally语句可以提供类似的功能,但是,需要一些额外代码的成本——更准确地说,是3个额外的代码行(尽管我们常常可以避免两个选项,并且使用Python为我们自动关闭文件):

由于这两个选项都需要比我们现在已经知道的更多的信息,我们将推迟到本书后面详细介绍。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文