文件的读写是编程中的常见操作,在Python中,对文件的处理非常简单。
打开文件
通过open()方法打开一个文件,并返回文件对象,需要传入两个参数:open(filename, mode)。例如:
>>> f = open('workfile', 'w')
第一个参数是包含文件名的字符串,第二个参数描述了文件被使用的方式,包括:
1)‘r‘:只读;
2)‘w‘:只写(如果文件已存在,将被覆盖);
3)‘a‘:添加,写入文件的数据将添加到文件结尾;
4)‘r+‘:同时支持读和写;
5)‘b‘:二进制模式(可添加到其它模式中使用)。
第二个参数是可选的,如果没填默认为‘r‘。
通常,文件以文本模式打开,也就是说,你读和写的字符串,被编码为一种特定的编码(默认为UTF-8)。如果文件是一个二进制文件,模式‘b‘可以以二进制方式打开文件:数据以二进制方式读和写,例如‘rb‘可以用来读取一个二进制文件。
在文本模式中读时,默认会将平台相关的行结束符(\n在Unix,\r\n在Windows)转换到\n;当文本模式写时,默认将行结束符\n转换到平台特定的结束符。这对于文本文件来说没有问题,但会毁坏二进制文件,例如JPEG或者EXE文件,因此当读写这类文件时应该采用二进制模式。
文件对象方法
通过open方法我们得到一个文件对象,下面介绍对象支持的方法。
read
下面的方法用于读去指定长度的数据:
f.read(size)
该方法读取的数据作为一个String或者bytes返回(根据打开文件的模式)。size参数可选,当size被忽略或者为负时,将读取整个文件的内容,如果文件过大,将导致内存溢出;当size为正时,最多size bytes的数据被读。如果到达文件结尾,f.read()将返回空字符串(‘‘)。
>>> f.read() 'This is the entire file.\n' >>> f.read() ''
文件对象的另一个方法是:
f.readline()
该方法用于读取一行数据:行数据将以行结束符(\n)结尾,注意最后一行数据如果不是以新行结束则没有行结束符。如果f.readline()返回一个空字符串,则表示到达文件结尾,一个空白行表示为‘\n‘。
>>> f.readline() 'This is the first line of the file.\n' >>> f.readline() 'Second line of the file\n' >>> f.readline() ''
如果需要读取文件中的所有行,则需要使用一个循环:
>>> for line in f: print(line, end='') This is the first line of the file. Second line of the file
如果你想要读取文件中的所有行到一个list中,你也可以使用list(f)或者f.readlines()。
write
f.write(string)用于写文件,返回写入的字符数:
>>> f.write('This is a test\n') 15
在写入其它数据类型到文件时,需要先转换到字符串:
>>> value = ('the answer', 42) >>> s = str(value) >>> f.write(s) 18
tell和seek
使用f.tell()可以得到文件对象的当前位置,在二进制模式时表示从文件开始的字节数,在文本模式则是字符数。
可以使用f.seek(offset, from_what)改变文件对象的位置,位置通过将offset加上参考点(from_what)得到。from_what值的含义为:
1)0:从文件头开始;
2)1:从当前位置开始;
3)2:从文件末尾开始。
如果忽略from_what,则默认值为0,从文件头开始。
>>> f = open('workfile', 'rb+') >>> f.write(b'0123456789abcdef') 16 >>> f.seek(5) # Go to the 6th byte in the file 5 >>> f.read(1) b'5' >>> f.seek(-3, 2) # Go to the 3rd byte before the end 13 >>> f.read(1) b'd'
在文本文件中(没有通过‘b‘模式打开的文件),只支持从文件头开始seek(seek(0, 2)将导致异常),offset只支持f.tell()的返回值或者0,其它值将导致未定义的行为。
close
当你处理完文件后,需要将文件关闭。f.close()将关闭文件,并且释放文件占有的系统资源。在调用f.close()后,任何尝试使用该文件的行为将失败。
>>> f.close() >>> f.read() Traceback (most recent call last): File "<stdin>", line 1, in ? ValueError: I/O operation on closed file
处理文件对象时,使用with关键字是一个好的实践。好处在于当文件使用结束后将被关闭,即使在使用过程中出现了异常。with的代码也比等价的try-finally块更短:
>>> with open('workfile', 'r') as f: read_data = f.read() >>> f.closed True
文件对象还有一些额外的方法,例如:isatty()和truncate(),但不常用。
保存json数据
文件中的字符串能够容易的被读和写,但数字则要麻烦点,需要做一些转换,例如:使用int()将读取的字符串转换为int。当你想保存一些复杂的数据结构时,例如嵌套list和字典,将更加复杂。
为了更好的支持复杂数据结构,Python提供了JSON (JavaScript Object Notation)作为中间数据格式。标准的模块叫做json,它能够将层级的数据转换为字符串表示,这个过程叫序列化;并且能将字符串重新组织为数据,叫做反序列化。序列化后的数据可以在文件中保存,或者通过网络传送给远程主机。
如果你有一个对象x,你能通过下面的方式将它转化为json字符串:
>>> json.dumps([1, 'simple', 'list']) '[1, "simple", "list"]'
dumps()的另一个变体,叫做dump(),简单的将对象序列化并存入文本文件:
json.dump(x, f)
下面的方法将x从文件中读出,并反序列化到对象:
x = json.load(f)
这个简单的序列化机制能处理列表和字典,但在JSON中序列化其它类实例则需要一些额外的工作,这将在介绍json模块时详述。