`
hcdh37hcdh
  • 浏览: 13306 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

深入Python3 (Dive Into Python3)笔记11--文件

 
阅读更多

深入Python3 (Dive Into Python3)笔记11--文件
2010年12月01日
  尚未出师,博客内容犹如笔记,比较杂乱简略
  
  
  
  
  
  
  
  
  
  
  
  
  a_file = open('examples/chinese.txt', encoding='utf-8') 在这个例子中,目录路径中使用的是斜杠(forward slash),但是我并没有说明我正在使用的操作系统。Windows使用反斜杠来表示子目录,但是Mac OS X和Linux使用斜杠。但是,在Python中,斜杠永远都是正确的,即使是在Windows环境下。  如果你需要获得默认编码的信息,则导入locale模块,然后调用locale.getpreferredencoding()。在我安装了Windows的笔记本上,它的返回值是'cp1252',但是在我楼上安装了Linux的台式机上边,它返回'UTF8'。你看,即使在我自己家里我都不能保证一致性(consistency)!你的运行结果也许不一样(即使在Windows平台上),这依赖于操作系统的版本和区域/语言选项的设置。这就是为什么每次打开一个文件的时候指定编码方式是如此重要了。  也许你会感到意外,再次读取文件不会产生一个异常。Python不认为到达了文件末尾(end-of-file)还继续执行读取操作是一个错误;这种情况下,它只是简单地返回一个空字符串。 由于你依旧在文件的末尾,继续调用read()方法只会返回一个空字符串。 
  seek()方法使定位到文件中的特定字节。 
  read()方法可以使用一个可选的参数,即所要读取的字符个数。 
  只要愿意,你甚至可以一次读取一个字符。 
  a_file.tell() 
  你是否已经注意到了?seek()和tell()方法总是以字节的方式计数,但是,由于你是以文本文件的方式打开的,read()方法以字符的个数计数。中文字符的UTF-8编码需要多个字节。而文件里的英文字符每一个只需要一个字节来存储,所以你可能会产生这样的误解:seek()和read()方法对相同的目标计数。而实际上,只有对部分字符的情况是这样的。  流对象a_file仍然存在;调用close()方法并没有把对象本身销毁。所以这并不是非常有效。  从技术上说,with语句创建了一个运行时环境(runtime context)。在这几个样例中,流对象的行为就像一个上下文管理器(context manager)。Python创建了a_file,并且告诉它正进入一个运行时环境。当with块结束的时候,Python告诉流对象它正在退出这个运行时环境,然后流对象就会调用它的close()方法。请阅读 附录B,"能够在with块中使用的类"以获取更多细节。
  with语句不只是针对文件而言的;它是一个用来创建运行时环境的通用框架(generic framework),告诉对象它们正在进入和离开一个运行时环境。如果该对象是流对象,那么它就会做一些类似文件对象一样有用的动作(就像自动关闭文件!)。但是那个行为是被流对象自身定义的,而不是在with语句中。还有许多跟文件无关的使用上下文管理器(context manager)的方法。在这章的后面可以看到,你甚至可以自己创建它们。  其实你可以舒口气了,因为Python默认会自动处理行的结束符。如果你告诉它,"我想从这个文本文件一次读取一行,"Python自己会弄明白这个文本文件到底使用哪种方式标记新行,然后正确工作。 
  如果想要细粒度地控制(fine-grained control)使用哪种新行标记符,你可以传递一个可选的参数newline给open()函数。请阅读open()函数的文档以获取更多细节。
  print('{:>4} {}'.format(line_number, a_line.rstrip()))
  使用字符串的format()方法,你可以打印出行号和行自身。格式说明符{:>4}的意思是"使用最多四个空格使之右对齐,然后打印此参数。"变量a_line是包括回车符等在内的完整的一行。字符串方法rstrip()可以去掉尾随的空白符,包括回车符。 你是否注意到当你在打开文件用于写入数据的时候传递给open()函数的encoding参数。它"非常重要",不要忽略了!就如你在这章开头看到的,文件中并不存在字符串,它们由字节组成。只有当你告诉Python使用何种编码方式把字节流转换为字符串,从文件读取"字符串"才成为可能。相反地,写入文本到文件面临同样的问题。实际上你不能直接把字符写入到文件;字符只是一种抽象。为了写入字符到文件,Python需要知道如何将字符串转换为字节序列。唯一能保证正确地执行转换的方法就是当你为写入而打开一个文件的时候,指定encoding参数。  用二进制模式打开文件很简单,但是很精细。与文本模式唯一不同的是mode参数包含一个字符'b'。 
  然而,确实有不同之处:二进制的流对象没有encoding属性。你能明白其中的道理的,对吧?现在你读写的是字节,而不是字符串,所以Python不需要做转换工作。从二进制文件里读出的跟你所写入的是完全一样的,所以没有执行转换的必要。 a_file = io.StringIO(a_string)  为了从字符串创建一个流对象,可以把想要作为"文件"使用的字符串传递给io.StringIO()来创建一个StringIO的实例。 你应该问题以二进制模式打开gzip压缩文件。(注意mode参数里的'b'字符。) 
  我在Linux系统上完成的这个例子。如果你对命令行不熟悉,这条命令用来显示刚才你在Python shell创建的gzip压缩文件的"长清单(long listings)",你可以看到,它有79个字节长。而实际上这个值比一开始的字符串还要长!由于gzip文件包括了一个固定长度的文件头来存放一些关于文件的元数据(metadata),所以它对于极小的文件来说效率不高。 
  gunzip命令(发音:"gee-unzip")解压缩文件然后保存其内容到一个与原来压缩文件同名的新文件中,并去掉其.gz扩展名。 
  cat命令显示文件的内容。当前文件包含了原来你从Python shell直接写入到压缩文件out.log.gz的那个字符串。 
  标准输出和标准错误(通常缩写为stdout和stderr)是被集成到每一个类UNIX操作系统中的两个管道(pipe),包括Mac OS X和Linux。当你调用print()的时候,需要打印的内容即被发送到stdout管道。当你的程序出错并且需要打印跟踪信息(traceback)时,它们被发送到stderr管道。默认地,这两个管道都被连接到你正在工作的终端窗口上(terminal window);当你的程序打印某些东西,你可以在终端上看到这些输出,当程序出错,你也可以从终端上看到这些错误信息。在图形化的Python shell里,stdout和stderr管道默认连接到"交互式窗口(Interactive Window)"  sys.stdout和sys.stderr都是流对象,尽管他们只支持写入。但是他们是变量而不是常量。这就意味着你可以给它们赋上新值 - 任意其他流对象 - 来重定向他们的输出。 
  as子句(clause)到哪里去了?其实with语句并不一定需要as子句。就像你调用一个函数然后忽略其返回值一样,你也可以不把with语句的上下文环境赋给一个变量。在这种情况下,我们只关心RedirectStdoutTo上下文环境的边际效应(side effect)。 
  那么,这些边际效应都是些什么呢?我们来看一看RedirectStdoutTo类的内部结构。这是一个用户自定义的上下文管理器(context manager)。任何类只要定义了两个特殊方法:code>__enter__()和__exit__()就可以变成上下文管理器。 
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics