Version:Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:44:40) [MSC v.1600 64 bit (AMD64)] on win32
文件与I/O
读写文本数据
使用带有rt
模式的open()
函数读取文本文件
|
|
类似的,为了写入一个文本文件,使用带有wt
模式的open()
函数,如果之前文件内容存在则清除并覆盖掉
|
|
如果是在已存在文件中添加内容,使用模式为at
的open()
函数。with
控制块结束时,文件会自动关闭。你也可以不使用with
语句,但是这时候你就必须记得手动关闭文件。
使用print输出元组
|
|
读写字节数据
使用模式为rb
或wb
的open()
函数来读取或写入二进制数据
|
|
在读取二进制数据的时候,字节字符串和文本字符串的语义差异可能会导致一个潜在的陷阱。特别需要注意的是,索引和迭代动作返回的是字节的值而不是字节字符串。
|
|
向不存在的文件中写入数据
如果只允许向不存在的文件写入数据,可以在open()
函数中使用x
模式来代替w
模式来解决这个问题。
|
|
由提示信息可知,当该文件在系统中已经存在的时候,是不允许继续向其中写入内容的。如果文件是二进制的,使用xb
来代替xt
。
字符串的I/O操作
使用io.StringIO()
和io.BytesIO()
类来创建类文件对象操作字符串数据
|
|
io.StringIO
只能用于文本。如果你要操作二进制数据,要使用io.BytesIO
类来代替
|
|
读写压缩文件
gzip
和bz2
模块可以很容易的处理这些文件。两个模块都为open()
函数提供了另外的实现来解决这个问题
|
|
类似的,为了写入压缩数据,可以这样做
|
|
大部分情况下读写压缩数据都是很简单的。但是要注意的是选择一个正确的文件模式是非常重要的。如果你不指定模式,那么默认的就是二进制模式,如果这时候程序想要接受的是文本数据,那么就会出错。
当写入压缩数据时,可以使用compresslevel
这个可选的关键字参数来指定一个压缩级别。
|
|
默认的等级是9
,也是最高的压缩等级。等级越低性能越好,但是数据压缩程度也越低。
最后一点,gzip.open()
和bz2.open()
还有一个很少被知道的特性,它们可以作用在一个已存在并以二进制模式打开的文件上。比如,下面代码是可行的:
|
|
这样就允许gzip
和bz2
模块可以工作在许多类文件对象上,比如套接字,管道和内存中文件等。
读取二进制数据到可变缓冲区中
|
|
|
|
文件对象的readinto()
方法能被用来为预先分配内存的数组填充数据,甚至包括由array
模块或numpy
库创建的数组。和普通read()
方法不同的是,readinto()
填充已存在的缓冲区而不是为新对象重新分配内存再返回它们。因此,你可以使用它来避免大量的内存分配操作。比如,如果你读取一个由相同大小的记录组成的二进制文件时,你可以像下面这样写:
|
|
文件路径名的操作
|
|
对于任何的文件名的操作,你都应该使用os.path
模块,而不是使用标准字符串操作来构造自己的代码。特别是为了可移植性考虑的时候更应如此,因为os.path
模块知道Unix
和Windows
系统之间的差异并且能够可靠地处理类似Data/data.csv
和Data\data.csv
这样的文件名。其次,你真的不应该浪费时间去重复造轮子。通常最好是直接使用已经为你准备好的功能。
使用如下方式测试文件的类型,如果测试的文件不存在的时候,结果都会返回False
|
|
如果你还想获取元数据(比如文件大小或者是修改日期),也可以使用os.path
模块来解决
|
|
使用os.listdir()
函数来获取某个目录中的文件列表
|
|
获取目录中的列表是很容易的,但是其返回结果只是目录中实体名列表而已。如果你还想获取其他的元信息,比如文件大小,修改时间等等,你或许还需要使用到os.path
模块中的函数或者os.stat()
函数来收集数据。
|
|
增加或改变已打开文件的编码
如果你想给一个以二进制模式打开的文件添加Unicode
编码/解码方式,可以使用io.TextIOWrapper()
对象包装它。
|
|
如果你想修改一个已经打开的文本模式的文件的编码方式,可以先使用detach()
方法移除掉已存在的文本编码层,并使用新的编码方式代替。
|
|
在文本模式打开的文件中写入原始的字节数据,将字节数据直接写入文件的缓冲区即可。
|
|
类似的,能够通过读取文本文件的buffer
属性来读取二进制数据。
创建临时文件和文件夹
tempfile
模块中有很多的函数可以完成这任务。为了创建一个匿名的临时文件,可以使用tempfile.TemporaryFile
:
|
|
TemporaryFile()
的第一个参数是文件模式,通常来讲文本模式使用w+t
,二进制模式使用w+b
。这个模式同时支持读和写操作,在这里是很有用的,因为当你关闭文件去改变模式的时候,文件实际上已经不存在了。TemporaryFile()
另外还支持跟内置的open()
函数一样的参数。
在大多数Unix
系统上,通过TemporaryFile()
创建的文件都是匿名的,甚至连目录都没有。如果你想打破这个限制,可以使用NamedTemporaryFile()
来代替。比如:
|
|
这里,被打开文件的f.name
属性包含了该临时文件的文件名。当你需要将文件名传递给其他代码来打开这个文件的时候,这个就很有用了。和TemporaryFile()
一样,结果文件关闭时会被自动删除掉。如果你不想这么做,可以传递一个关键字参数delte=False
即可。比如:
|
|
为了创建一个临时目录,可以使用tempfile.TemporaryDirectory()
|
|
TemporaryFile()
、NamedTemporaryFile()
和TemporaryDirectory()
函数应该是处理临时文件目录的最简单的方式了,因为它们会自动处理所有的创建和清理步骤。在一个更低的级别,你可以使用mkstemp()
和mkdtemp()
来创建临时文件和目录。
与串行端口的数据通信
尽管你可以通过使用Python内置的I/O模块来完成这个任务,但对于串行通信最好的选择是使用pySerial包。这个包的使用非常简单,先安装pySerial
,使用类似下面这样的代码就能很容易的打开一个串行端口:
|
|
设备名对于不同的设备和操作系统是不一样的。比如,在Windows
系统上,你可以使用0,1等表示的一个设备来打开通信端口COM0
和COM1
。一旦端口打开,那就可以使用read()
,readline()
和write()
函数读写数据了。
|
|
序列化Python对象
对于序列化最普遍的做法就是使用pickle
模块。为了将一个对象保存到一个文件中,可以这样做:
|
|
为了将一个对象转储为一个字符串,可以使用pickle.dumps()
:s = pickle.dumps(data)
为了从字节流中恢复一个对象,使用picle.load()
或pickle.loads()
函数。比如:
|
|
数据编码和处理
读写CSV数据
|
|
另外一个选择就是将数据读取到一个字典序列中去。
|
|
在这个版本中,你可以使用列名去访问每一行的数据了。比如,row['Symbol']
或者row['Change']
。
为了写入CSV
数据,你仍然可以使用CSV
模块,不过这时候先创建一个writer
对象。
|
|
如果你有一个字典序列的数据,可以像这样做
|
|
读写JSON数据
json
模块提供了一种很简单的方式来编码和解码JSON数据。其中两个主要的函数是json.dumps()
和json.loads()
,要比其他序列化函数库如pickle
的接口少得多。
|
|
将JSON编码的字符串转回一个Python数据结构data = json.loads(json_str)
如果你要处理的是文件而不是字符串,你可以使用json.dump()
和json.load()
来编码和解码JSON数据。
|
|
解析简单的XML数据
可以使用xml.etree.ElementTree
模块从简单的XML文档中提取数据。
|
|
xml.etree.ElementTree.parse()
函数解析整个XML文档并将其转换成一个文档对象。然后,你就能使用find()
、iterfind()
和findtext()
等方法来搜索特定的XML元素了。这些函数的参数就是某个指定的标签名,例如channel/item
或title
。
ElementTree
模块中的每个元素有一些重要的属性和方法,在解析的时候非常有用。tag
属性包含了标签的名字,text
属性包含了内部的文本,而get()
方法能获取属性值。
有一点要强调的是xml.etree.ElementTree
并不是XML
解析的唯一方法。对于更高级的应用程序,你需要考虑使用lxml
。它使用了和ElementTree
同样的编程接口,因此上面的例子同样也适用于lxml
。你只需要将刚开始的import
语句换成from lxml.etree import parse
就行了。lxml
完全遵循XML
标准,并且速度也非常快,同时还支持验证,XSLT
和XPath
等特性。
增量式解析大型XML文件
任何时候只要你遇到增量式的数据处理时,第一时间就应该想到迭代器和生成器。 下面是一个很简单的函数,只使用很少的内存就能增量式的处理一个大型XML文件。
|
|
iterparse()
方法允许对XML
文档进行增量操作。使用时,你需要提供文件名和一个包含下面一种或多种类型的事件列表:start
,end
,start-ns
和end-ns
。由iterparse()
创建的迭代器会产生形如(event, elem)的元组,其中event
是上述事件列表中的某一个,而elem
是相应的XML元素。
start
事件在某个元素第一次被创建并且还没有被插入其他数据(如子元素)时被创建。而end
事件在某个元素已经完成时被创建。尽管没有在例子中演示,start-ns
和end-ns
事件被用来处理XML
文档命名空间的声明。
将字典转换为XML
|
|
对于I/O
操作,使用xml.etree.ElementTree
中的tostring()
函数很容易就能将它转换成一个字节字符串。
|
|
xml.sax.saxutils
中的escape()
和unescape()
函数提供对HTML实体的转换方法
|
|
解析和修改XML
|
|
编码和解码十六进制数
|
|
类似的功能同样可以在base64
模块中找到
|
|
大部分情况下,通过使用上述的函数来转换十六进制是很简单的。上面两种技术的主要不同在于大小写的处理。函数base64.b16decode()
和base64.b16encode()
只能操作大写形式的十六进制字母,而binascii
模块中的函数大小写都能处理。
还有一点需要注意的是编码函数所产生的输出总是一个字节字符串。如果想强制以Unicode
形式输出,你需要增加一个额外的界面步骤。例如:
|
|
在解码十六进制数时,函数b16decode()
和a2b_hex()
可以接受字节或unicode
字符串。但是,unicode
字符串必须仅仅只包含ASCII
编码的十六进制数。
编码解码Base64数据
base64
模块中有两个函数b64encode()
andb64decode()
可以帮你解决这个问题。
|
|
读写二进制数组数据
可以使用struct
模块处理二进制数据。下面是一段示例代码将一个Python元组列表写入一个二进制文件,并使用struct
将每个元组编码为一个结构体。
|
|
如果你打算以块的形式增量读取文件,你可以这样做:
|
|
如果你想将整个文件一次性读取到一个字节字符串中,然后在分片解析。那么你可以这样做:
|
|
参考文献
[1] A Byte of Python3
[2] python3-cookbook