文件最重要的功能是提供和接收数据。
如果有一个名为 f 的类似于文件的对象,
可使用 f.write 来写入数据,还可使用 f.read 来读取数据。
与Python的其他大多数功能一样,在哪些东西可用作数据方面,也存在一定的灵活性,
但在文本和二进制模式下,基本上分别将 str 和 bytes 类用作数据。
在熟悉了处理文件夹和相对路径后,就可以指定文件的位置,
进行读写。接下来几节介绍的函数适用于纯文本文件。
“纯文本文件”只包含基本文本字符,不包含字体、
大小和颜色信息。带有 .txt 扩展名的文本文件,
以及带有 .py 扩展名的 Python 脚本文件,
都是纯文本文件的例子。
它们可以被 Windows 的 Notepad 或 OS X 的 TextEdit
应用打开。程序可以轻易地读取纯文本文件的内容,
将它们作为普通的字符串值。
r以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。rb以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。r+打开一个文件用于读写。文件指针将会放在文件的开头。rb+以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。w打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。wb以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。w+打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。wb+以二进制格式打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。a打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。换言之,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。ab以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。换言之,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。a+打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。ab+以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。
with open('xx_hello.txt', 'w') as fo:
fo.write("Hello.")
开始:
helloFile = open('xx_hello.txt')
以上代码以相对路径方式打开当前路径下的文件。可以通过绝对路径定位系统中的文件。
在Python中打开文件时,读模式是默认的模式。
但如果不希望依赖于Python的默认值,也可以明确指明该模式,向 open() 传入字符串 'r' ,作为第二个参数。
所以 open('/Users/asweigart/hello.txt','r') 和 open('/Users/asweigart/hello.txt') 做的事情一样。
调用 open() 将返回一个File对象。
File 对象代表计算机中的一个文件,
它只是Python中另一种类型的值,
就像已熟悉的列表和字典。
在前面的例子中,将 File 对象保存在helloFile 变量中。
现在,当需要读取或写入该文件,就可以调用 helloFile 变量中的 File 对象的方法。
读取文件内容
既然有了一个 File 对象,就可以开始从它读取内容。
如果希望将整个文件的内容读取为一个字符串值,
就使用 File 对象的 read()方法。
继续使用保存在 helloFile 中的
hello.txt File 对象,在交互式环境中输入以下代码:
helloContent = helloFile.read()
helloContent
'Hello.'
如果将文件的内容看成是单个大字符串,read()方法就返回保存在该文件中的这个字符串。
或者,可以使用readlines()方法,从该文件取得一个字符串的列表。
列表中的每个字符串就是文本中的每一行。
import pprint
pprint.pprint(open(r'xx_hello.txt').readlines())
['Hello.']
请注意,这里利用了文件对象将被自动关闭这一事实。
写入文件
Python 允许将内容写入文件,
方式与 print() 函数将字符串“写”到屏幕上类似。
但是,如果打开文件时用读模式,就不能写入文件。
需要以“写入纯文本模式”或“添加纯文本模式”
打开该文件,或简称为“写模式”和“添加模式”。
写模式将覆写原有的文件,从头开始,就像用一个新值覆写一个变量的值。
将 'w' 作为第二个参数传递给 open() ,以写模式打开该文件。
不同的是,添加模式将在已有文件的末尾添加文本。
可以认为这类似向一个变量中的列表添加内容,
而不是完全覆写该变量。将 'a' 作为第二个参数传递给 open(),以添加模式打开该文件。
如果传递给 open() 的文件名不存在,
写模式和添加模式都会创建一个新的空文件。
在读取或写入文件后,
调用 close() 方法,然后才能再次打开该文件。
整合这些概念,在交互式环境中输入以下代码:
baconFile = open('xx_hello.txt','w')
baconFile.write('Hello world!\n')
13
baconFile.close()
baconFile = open('xx_hello.txt', 'a')
baconFile.write('Bacon is not a vegetable.')
25
baconFile.close()
baconFile = open('xx_hello.txt')
content = baconFile.read()
baconFile.close()
print(content)
Hello world! Bacon is not a vegetable.
首先,以写模式打开 bacon.txt 。
因为还没有 bacon.txt ,Python 就创建了一个。
在打开的文件上调用 write() ,
并向 write() 传入字符串参数 'Hello world! \n',
将字符串写入文件,并返回写入的字符个数,
包括换行符。然后关闭该文件。
为了将文本添加到文件已有的内容,
而不是取代刚刚写入的字符串,
就以添加模式打开该文件。
向该文件写入'Bacon is not a vegetable.',
并关闭它。最后,为了将文件的内容打印到屏幕上,
以默认的读模式打开该文件,调用 read(),
将得到的内容保存在 content 中,
关闭该文件,并打印 content 。
请注意, write() 方法不会像 print()函数那样,
在字符串的末尾自动添加换行字符。必须自己添加该字符。
在 Python 中,读写文件有3个步骤:
- 调用
open()函数,返回一个File对象。 - 调用
File对象的read()或write()方法。 - 别忘了调用方法
close将文件关闭。
通常,程序退出时将自动关闭文件对象(也可能在退出程序前这样做), 因此是否将读取的文件关闭并不那么重要。 然而,关闭文件没有坏处,在有些操作系统和设置中,还可避免无意义地锁定文件以防修改。 另外,这样做还可避免用完系统可能指定的文件打开配额。
对于写入过的文件,一定要将其关闭,因为Python可能缓冲写入的数据(将数据暂时存储在某个地方,以提高效率)。
因此如果程序因某种原因崩溃,数据可能根本不会写入到文件中。
安全的做法是,使用完文件后就将其关闭。
如果要重置缓冲,让所做的修改反映到磁盘文件中, 但又不想关闭文件,可使用方法 flush 。
然而,需要注意的是,根据使用的操作系统和设置,flush 可能出于锁定考虑而禁止其他正在运行的程序访问这个文件。
只要能够方便地关闭文件,就应将其关闭。
要确保文件得以关闭,可使用一条 try/finally 语句,并在 finally 子句中调用 close 。
# 在这里打开文件
try:
# 将数据写入到文件中
finally:
file.close()
实际上,有一条专门为此设计的语句,那就是 with 语句。
with open("somefile.txt") as somefile:
do_something(somefile)
with 语句能够打开文件并将其赋给一个变量(这里是 somefile )。
在语句体中,将数据 写入文件(还可能做其他事情)。
到达该语句末尾时,将自动关闭文件,即便出现异常亦如此。
with 语句实际上是一个非常通用的结构,允许使用所谓的上下文管理器。
上下文管理器是支持两个方法的对象: enter 和 exit 。
方法 enter 不接受任何参数,在进入 with 语句时被调用,其返回值被赋给关键字 as 后面的变量。
方法 exit 接受三个参数:异常类型、异常对象和异常跟踪。
它在离开方法时被调用。如果 exit 返回 False ,将抑制所有的异常。
文件也可用作上下文管理器。它们的方法 enter 返回文件对象本身,而方法 exit 关闭文件。
下面来尝试写入,首先是 write(string) 。
f = open(r'xx_hello.txt', 'w')
f.write('this\nis no\nhaiku')
f.close()
!more somefile.txt
more: cannot open somefile.txt: No such file or directory
最后是 writelines(list) :
f = open(r'xx_hello.txt')
lines = f.readlines()
f.close()
lines[1] = "isn't a\n"
f = open(r'xx_hello.txt', 'w')
f.writelines(lines)
f.close()
查看这个文件:
!more xx_hello.txt
this isn't a haiku
又例如,在 hello.txt 文件相同的目录下,
创建一个名为 xx_sonnet29.txt 的文件,
并在其中写入以下文本:
When, in disgrace with fortune and men's eyes ,
I all alone beweep my outcast state,
And trouble deaf heaven with my bootless cries,
And look upon myself and curse my fate,
with open("xx_sonnet29.txt", "w") as f:
f.write('''When, in disgrace with fortune and men's eyes ,
I all alone beweep my outcast state,
And trouble deaf heaven with my bootless cries,
And look upon myself and curse my fate,''')
确保用换行分开这4行。 然后在交互式环境中输入以下代码:
sonnetFile = open('xx_sonnet29.txt')
sonnetFile.readlines()
["When, in disgrace with fortune and men's eyes ,\n", ' I all alone beweep my outcast state,\n', ' And trouble deaf heaven with my bootless cries, \n', ' And look upon myself and curse my fate,']
请注意,每个字符串值都以一个换行字符 \n 结束。
除了文件的最后一行。与单个大字符串相比,
字符串的列表通常更容易处理。
在 Bash 等 Shell 中,可依次输入多个命令,并使用管道将它们链接起来,如下所示:
$ cat somefile.txt | python somescript.py | sort
这条管道线包含三个命令:
- cat
somefile.txt:将文件somefile.txt的内容写入到标准输出(sys.stdout)。 - python
somescript.py:执行Python脚本somescript。这个脚本从其标准输入中读取,并将结果写入到标准输出。 - sort:读取标准输入(
sys.stdin)中的所有文本,将各行按字母顺序排序,并将结果写入到标准输出。
但这些管道字符( | )有何作用呢?
脚本 somescript.py 的作用是什么呢?
管道将一个命令的标准输出链接到下一个命令的标准输入。
很聪明吧? 因此可以认为, somescript.py 从其 sys.stdin 中读取数据(这些数据是 somefile.txt 写入的),
并将结果写入到其 sys.stdout( sort 将从这里获取数据)。
代码示例1:计算 sys.stdin 中包含多少个单词的简单脚本使用 sys.stdin 的简单脚本( somescript.py ):
somescript.py
import sys
text = sys.stdin.read()
words = text.split()
wordcount = len(words)
print('Wordcount:', wordcount)
Wordcount: 0
代码示例2:一个内容荒谬的文本文件显示了文件 somefile.txt 的内容:
Your mother was a hamster and your
father smelled of elderberries.
cat somefile.txt | python somescript.py 的结果如下:
Wordcount: 11
在本章中,将文件都视为流,只能按顺序从头到尾读取。
实际上,可在文件中移动, 只访问感兴趣的部分(称为随机存取)。
为此,可使用文件对象的两个方法:seek() 和 tell() 。
方法 seek(offset[, whence]) 将当前位置(执行读取或写入的位置)移到 offset 和 whence 指定的地方。
参数 offset 指定了字节(字符)数,
而参数 whence 默认为 io.SEEK_SET(0),
这意味着偏移量是相对于文件开头的(偏移量不能为负数)。
参数 whence 还可设置为 io.SEEK_CUR(1) 或 io.SEEK_END(2) ,
其中前者表示相对于当前位置进行移动(偏移量可以为负),
而后者表示相对于文件末尾进行移动。请看下面的示例:
thefile = 'xx_hello.txt'
f = open( thefile , 'w')
f.write('01234567890123456789')
f.seek(5)
5
f.write('Hello, World!')
13
f.close()
f = open( thefile )
f.read()
'01234Hello, World!89'
方法 tell() 返回当前位于文件的什么位置,如下例所示:
f = open( thefile )
f.read(3)
f.read(2)
'34'
f.tell()
5