Python文件操作精讲
如果希望将数据长久保存,最简单的办法就是将数据写入磁盘文件中。这样在程序退出后,处理结果依然长期有效。对于大型软件项目,文件操作是无法避免的。
下面是打开某个文本文件,并将其内容显示在屏幕上的代码:
文件名可以包含路径,如 cfg/config.ini。使用绝对路径和相对路径都是允许的,但不能使用通配符,如 log/*.log。对于 Windows 用户来说,由于使用 \ 作为路径分隔符,而有人喜欢用两个连续的反斜杠 \ 即 \\ 来表示 \,如"c:\\log\\app.log"。推荐的用法是在引号前面加上 r,这样看起来更加自然一点,如 r"c:\log\app.log"。
打开方式包括:只读,用 r 表示;只写,用 w 表示;添加,用 a 表示。除此之外,还包括可读可写,用 w+ 或者 r+ 表示。它们的区别是 w+ 会清空原来的文件内容,而 r+ 不会清空原来的文件内容。如 rb 即表示用二进制模式 + 只读打开指定文件。
如果操作的文件不存在或者没有权限进行相关操作时,其会抛出 FileNotFoundError 或者 IOError 异常,此时一般需要使用 try 语句来处理。下面是在 Python 3 中打开不存在的文件的情况:
参数 size 如果为正数,表示最多读出 size 个字符;如果 size 为 0,则什么也不会读出,返回值是空字符串;如果 size 为负数,表示读出全部的内容。size 的默认值是 -1,表示读出全部的内容。
下面的例子演示了不指定 size 的值而使用默认值 -1 的情况。
下面演示指定 size,并且 size 为正数的情况。
如果到了文件的尾部,则返回空字符串。
下面的例子演示了没有指定 size 而使用默认值 -1 的情况。
下面的例子演示了size为正数的情况。
下面的例子演示了size为0的情况。
参数 hint 用来限制读入的行数。如果参数 hint 为负数或者 0,表示没有行数的限制。hint 的默认值是 -1,即默认情况下是不对读入的行数进行限制的,返回的是文件的所有行。
下面的例子演示了没有指定 hint 值而使用默认值 -1 的情况,其会读出所有的行,并且将这些行组成一个列表返回。
如果 hint 为正数,则会依次读入各行,并检查读入的字符数是否大于 hint。如果大于或等于 hint,则停止继续读入下一行;如果小于 hint 则继续读入下一行。下面的例子演示了 hint 比实际文件字节数小的情况。
我们可以用 tell() 来得到当前位置,其返回一个整数。下面的例子演示了 tell() 的用法。
该函数有 2 个参数,第一个参数是 offset,表示偏移量,可以为负数;第二个参数是 whence,表示相对于什么,可以是相对文件的头、文件的尾、当前文件。whence 的默认值是 0,表示文件头,其还可以为1表示当前位置,或者为2表示文件尾部。
下面的例子将打开文件,然后将当前位置移动到尾部的前 2 个字符,这样下次读到的就是文件最后面的两个字符。该文件的最后两个字符是yz。这里需要注意的是,文件一定要以二进制模式打开,否则 seek() 会抛出异常。下面是完整代码:
下面的例子查看了普通文件的编号以及 3 个特殊文件的编号。
在文件关闭后便不能对其进行读写操作。文件关闭后,文件对象还是存在的,但其属性 closed 现在为 True,表示该文件已经被关闭了。
声明:《Python系列教程》为本站“54笨鸟”官方原创,由国家机构和地方版权局所签发的权威证书所保护。
注意,本节主要介绍普通文本文件和二进制文件的操作方法,对于 json、yaml、cvs、xml 等特殊格式的文件,一般都有对应的包来进行操作,不必直接使用本节介绍的方法来处理。
文件的基本操作
文件的基本操作步骤如下:- 打开文件。
- 进行读写操作。
- 关闭文件。
下面是打开某个文本文件,并将其内容显示在屏幕上的代码:
fd = open("in.dat", "r") # 打开文件in.dat for line in fd: # 读取in.dat的每一行到变量line中 print(line) # 在屏幕上打印出line的内容 fd.close() # 处理结束,关闭文件如果希望将数据写入文件中,可以使用下面的基本操作模式:
fd = open("out.dat", "r") # 以写的方式打开文件out.dat fd.write("output line 1") # 向该文件写入一行数据 fd.write("output line 2") # 再次向该文件写入一行数据 fd.close() # 处理结束,关闭文件如果希望添加数据到某个文件的尾部,如将一些新的日志内容添加到日志文件的尾部,则需要设定文件打开的模式为 a,这样原来文件的数据不会丢失,写入的数据只是添加在原来数据的尾部。下面的代码演示了这样的用法:
fd = open("out.dat", "a") # a表示是以添加的方式打开该文件 fd.write("log line 1") # 在尾部添加一行日志 fd.write("log line 2") # 再次在尾部添加一行日志 fd.close() # 处理结束,关闭文件
打开文件
打开文件可以使用“open(文件名,模式)”来完成。该函数有两个参数,第一个参数是文件名,第二个参数是打开的模式。该函数返回一个文件对象,以后的读写都需要使用该文件对象。文件名可以包含路径,如 cfg/config.ini。使用绝对路径和相对路径都是允许的,但不能使用通配符,如 log/*.log。对于 Windows 用户来说,由于使用 \ 作为路径分隔符,而有人喜欢用两个连续的反斜杠 \ 即 \\ 来表示 \,如"c:\\log\\app.log"。推荐的用法是在引号前面加上 r,这样看起来更加自然一点,如 r"c:\log\app.log"。
模式的基本格式如下:模式参数也是一个字符串,通过不同的模式值可以指定按照只读、只写、尾部添加等方式来打开某个文件。
mode = 打开方式 + 文件类型
文件类型包括两种,文本模式和二进制模式。文本模式用 t 表示,这是默认值;二进制模式用 b 表示。打开方式包括:只读,用 r 表示;只写,用 w 表示;添加,用 a 表示。除此之外,还包括可读可写,用 w+ 或者 r+ 表示。它们的区别是 w+ 会清空原来的文件内容,而 r+ 不会清空原来的文件内容。如 rb 即表示用二进制模式 + 只读打开指定文件。
如果操作的文件不存在或者没有权限进行相关操作时,其会抛出 FileNotFoundError 或者 IOError 异常,此时一般需要使用 try 语句来处理。下面是在 Python 3 中打开不存在的文件的情况:
>>> fd = open("notExists.dat", "r") # 打开不存在的文件,抛出异常 Traceback (most recent call last): File "<stdin>", line 1, in <module> FileNotFoundError: [Errno 2] No such file or directory: 'notExists.dat'下面是在 Python 2 中打开不存在的文件的情况:
>>> fd = open("notExists.dat", "r") # Python 2中的异常情况 Traceback (most recent call last): File "<stdin>", line 1, in <module> IOError: [Errno 2] No such file or directory: 'notExists.dat'为了处理这些打开文件的异常情况,可以使用下面的代码:
try: file_obj1 = open(u"nonexist.txt", "r") file_obj1.close() except IOError: # 找不到文件时提示文件不存在 print(u"File not Exist")如果希望某个文件只在某个局部有效,可以使用 with 语句。下面是一个使用的例子:
>>> with open('in.dat', 'r') as f: # 使用with语句,f是打开的文件对象 ... print(f.read()) # 读出所有的数据并打印到屏幕上 ... # 结束with语句 this is input text file # 文件内容 it contains 3 lines this is the end of file >>> f # 查看f <_io.TextIOWrapper name='in.dat' mode='r' encoding='UTF-8'> >>> f.closed # f是不是自动关闭了? True # 文件对象自动关闭了
文件对象的操作
通过打开文件得到文件对象,该对象提供一系列操作文件的方法。1) read(size):读入指定长度的文本
该函数从当前位置开始读,读出指定个数的字符。其返回值是一个字符串,表示读取的文件内容。参数 size 如果为正数,表示最多读出 size 个字符;如果 size 为 0,则什么也不会读出,返回值是空字符串;如果 size 为负数,表示读出全部的内容。size 的默认值是 -1,表示读出全部的内容。
下面的例子演示了不指定 size 的值而使用默认值 -1 的情况。
>>> fd = open("in.dat", "r") # 以只读方式打开文件in.dat >>> ret_str = fd.read() # 将所有文件内容读到ret_str,size=-1 >>> type(ret_str) # 返回值类型是字符串 <class 'str'> >>> len(ret_str) # 字符串长度为68 68 >>> print(ret_str) # 显示文件内容 this is input text file it contains 3 lines this is the end of file >>> fd.close() # 关闭文件
下面演示指定 size,并且 size 为正数的情况。
>>> fd = open("in.dat", "r") # 以只读方式打开文件in.dat >>> str1 = fd.read(40) # 读入最多40个字符,保存到str1中 >>> str2 = fd.read(40) # 读入最多40个字符,保存到str2中 >>> len(str1) # str1包含40个字符 40 >>> len(str2) # str2包含28个字符,总共是68个字符 28 >>> print(str1+str2) # 将str1和str2连接起来,就是文件的完整内容 this is input text file it contains 3 lines this is the end of file >>> fd.close() # 关闭文件
如果到了文件的尾部,则返回空字符串。
>>> fd = open("in.dat", "r") # 以只读方式打开文件in.dat >>> str1 = fd.read() # 读出全部内容 >>> str2 = fd.read() # 这时已经到了文件的尾部 >>> type(str2) # 返回值类型是字符串 <class 'str'> >>> len(str2) # str2的长度为0,所以是空字符串 0 >>> fd.close() # 关闭文件
2) readline(size):读入一行数据
该函数读入一行数据,所以文件类型要求是文本,不能是二进制。返回值是这行数据,包括尾部的换行符;如果没有数据则返回一个空的字符串。该函数也带有参数 size,表示的含义和 read() 一样。size 的默认值也是 -1,表示读取完整的一行。下面的例子演示了没有指定 size 而使用默认值 -1 的情况。
>>> fd = open("in.dat", "r") # 以只读方式打开文件in.dat >>> line = fd.readline() # 读入一行 >>> while line: # 如果不是空行,就是还没有到尾部 ... print(line, end='') # 打印读入的行,关闭自动换行功能 ... line = fd.readline() # 读入下一行 ... # 结束while循环 this is input text file # 显示的文件内容 it contains 3 lines this is the end of file >>> fd.close() # 关闭文件
下面的例子演示了size为正数的情况。
>>> fd = open("in.dat", "r") # 以只读方式打开文件in.dat >>> line = fd.readline(2) # 读入一行,但最多读入2个字符 >>> len(line) # 返回字符串的长度为2 2 >>> line # 显示返回值的内容 'th' >>> fd.close() # 关闭文件
下面的例子演示了size为0的情况。
>>> fd = open("in.dat", "r") # 以只读方式打开文件in.dat >>> line = fd.readline(0) # 读入一行,但是最多只能读入0个字符 >>> len(line) # 返回的是空字符串 0 >>> fd.close() # 关闭文件
3) readlines(hint):读出全部行
该函数将文件的每行作为一个元素,组合成一个列表返回。参数 hint 用来限制读入的行数。如果参数 hint 为负数或者 0,表示没有行数的限制。hint 的默认值是 -1,即默认情况下是不对读入的行数进行限制的,返回的是文件的所有行。
下面的例子演示了没有指定 hint 值而使用默认值 -1 的情况,其会读出所有的行,并且将这些行组成一个列表返回。
>>> fd = open("in.dat", "r") # 以只读方式打开文件in.dat >>> lines = fd.readlines() # 将所有的行读出 >>> lines # 显示返回值,是一个列表,每个元素表示一行 ['this is input text file\n', 'it contains 3 lines\n', 'this is the end of file\n'] >>> fd.close() # 关闭文件
如果 hint 为正数,则会依次读入各行,并检查读入的字符数是否大于 hint。如果大于或等于 hint,则停止继续读入下一行;如果小于 hint 则继续读入下一行。下面的例子演示了 hint 比实际文件字节数小的情况。
>>> fd = open("in.dat", "r") # 以只读方式打开文件in.dat >>> lines = fd.readlines(3) # 如果读入字符数超过3,就停止读入下一行 >>> lines # 所以只读入了一行便停止了 ['this is input text file\n'] >>> lines = fd.readlines(30) # 如果读入超过了30个字符,就停止读入下一行 >>> lines # 第二行字符串小于30,所以继续读入第三行 ['it contains 3 lines\n', 'this is the end of file\n'] >>> fd.close() # 关闭文件
4) write(data):写入字符串
在 Python 3 中,该函数的返回值是参数 data 的字节数。在 Python 2 中,其返回值是 None。下面演示了这种不同:>>> fd = open("out.dat", "w") # Python 3中的情况 >>> fd.write("line 1") # 写入字符串,返回值是字符的个数 6 >>> fd.close() 5 >>> fd = open("out.dat", "w") # Python 2中的情况下打开文件 >>> fd.write("line 1") # 写入字符串,返回值为None >>> fd.close()
5) writelines(lines):写入多行
lines 是一个列表或者元组,其执行效果相当于是 write(‘’.join(lines)),各行之间并不会填充任何数据。>>> fd = open("out.dat", "w") # 打开文件out.dat >>> fd.writelines(["line1", "line2", "line3"]) # 写入字符串列表 >>> fd.close() # 关闭文件 >>> fdr = open("out.dat", "r") # 查看写入的内容 >>> fdr.read() # 读入文件内容 'line1line2line3' # 行与行之间是没有添加任何信息的 >>> fdr.close() # 关闭fdr >>> fd = open("out.dat", "w") # 打开文件out.dat >>> fd.writelines(("line1", "line2", "line3")) # 写入字符串元组 >>> fd.close() # 关闭文件 >>> fdr = open("out.dat", "r") # 检查写入的数据 >>> fdr.read() # 可以发现没有添加数据在行之间 'line1line2line3' >>> fdr.read()
6) tell():得到文件位置
文件可以被看作是字节流或者字符流。第一个读入的字符是在该流的第 0 个位置上。如果读入了 5 个字符,则现在在该流的第 5 个位置上。我们可以用 tell() 来得到当前位置,其返回一个整数。下面的例子演示了 tell() 的用法。
try: file_obj1 = open(u"data.txt", "r") pos = file_obj1.tell() # 最开始,位置应该为0 print(u"1)当前位置为%d" % pos) data = file_obj1.read(5) # 读出5个字节 print(u"读出了%d个字节" % len(data)) pos = file_obj1.tell() print(u"2)当前位置为%d" % pos) file_obj1.close() except IOError: # 找不到文件时提示文件不存在 print(u"File not Exist")执行该脚本,输出如下:
E:>python tellDemo1.py
1)当前位置为0
读出了5个字节
2)当前位置为5
7) seek(offset,whence):设定当前位置
可以使用该函数调整当前所在的位置。例如,我们从文件头部读取了 1000 个字节,处理这 1000 个字节后发现还有一个很重要的信息在文件的第 3 个字节,此时可以将当前位置移动到相对头部 3 个字节的位置,这样下次 read() 操作便可以得到希望得到的信息。该函数有 2 个参数,第一个参数是 offset,表示偏移量,可以为负数;第二个参数是 whence,表示相对于什么,可以是相对文件的头、文件的尾、当前文件。whence 的默认值是 0,表示文件头,其还可以为1表示当前位置,或者为2表示文件尾部。
下面的例子将打开文件,然后将当前位置移动到尾部的前 2 个字符,这样下次读到的就是文件最后面的两个字符。该文件的最后两个字符是yz。这里需要注意的是,文件一定要以二进制模式打开,否则 seek() 会抛出异常。下面是完整代码:
try: # 必须以二进制模式打开文件,所以带上b这个标识 file_obj1 = open(u"data.txt", "rb") pos = file_obj1.tell() print(u"1)当前位置为%d" % pos) file_obj1.seek(-2, 2) print(u"2)当前位置为%d" % pos) data = file_obj1.read(2) print(u"读出了%d个字节" % len(data)) print("data = [%s]" % str(data)) pos = file_obj1.tell() print(u"3)当前位置为%d" % pos) file_obj1.close() except IOError: # 找不到文件时提示文件不存在 print(u"File not Exist")运行该程序,可以得到如下输出结果:
E:\>python seekDemo1.py
1)当前位置为0
2)当前位置为0
读出了2个字节
data = [b'yz']
3)当前位置为26
try: file_obj1 = open(u"data.txt", "rb") file_obj1.seek(0, 2) end_pos = file_obj1.tell() print(u"文件大小为%d" % end_pos) file_obj1.close() except IOError: # 找不到文件时提示文件不存在 print(u"File not Exist")
8) flush():刷新
该函数用于将文件缓存清空,这样我们做的修改就会保存到文件中。9) fileno():得到文件编号
该函数用于得到文件在进程中的编号,这是一个整数值。其中,stdin 在进程中的文件编号永远是 0,stdout 永远是 1,stderr 永远是 2,其他文件的编号都大于 2。下面的例子查看了普通文件的编号以及 3 个特殊文件的编号。
>>> import sys # 引入sys模块 >>> fd = open("./in.dat", "rb") # 打开一个普通文件 >>> fd.fileno() # 得到该文件的编号 3 >>> fd.close() # 关闭该文件 >>> sys.stdin.fileno() # 得到stdin的文件编号 0 >>> sys.stdout.fileno() # 得到stdout的文件编号 1 >>> sys.stderr.fileno() # 得到stderr的文件编号 2如果该文件已经被关闭,则 fileno() 会抛出 ValueError 异常。下面的代码演示了这种情况。
>>> import sys >>> fd = open("./in.dat", "rb") # 打开文件 >>> fd.fileno() 3 >>> fd.close() # 关闭文件 >>> fd.fileno() # 无法得到文件编号,抛出异常ValueError Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: I/O operation on closed file
关闭文件
在文件使用完毕后,需要关闭文件以释放资源。关闭文件的方法是:文件对象.close()
可以对一个已经关闭的文件再次执行 close() 操作,不必担心会产生异常。在文件关闭后便不能对其进行读写操作。文件关闭后,文件对象还是存在的,但其属性 closed 现在为 True,表示该文件已经被关闭了。
文件关闭后,除了 closed 外,文件的其他属性并不会发生变化,如 name、mode 等属性还是有效的,能够被继续使用。文件关闭后,如果尝试对其进行读写操作,则会抛出 ValueError 异常。
>>> fd = open("in.dat", "r") # 打开文件 >>> fd.closed # closed的值为False,表示没有关闭 False >>> fd.close() # 关闭该文件 >>> fd.closed # 现在closed的值为True True >>> fd.read() # 如果试图进行读操作,则抛出异常 Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: I/O operation on closed file. >>> fd.name # 查看name属性,依然有效 'in.dat' >>> fd.mode # 查看mode属性,依然有效 'r'
声明:《Python系列教程》为本站“54笨鸟”官方原创,由国家机构和地方版权局所签发的权威证书所保护。