21

Python中文件操作

 4 years ago
source link: https://www.tuicool.com/articles/nq2auaY
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

1 文件操作

无论在那种语言中都会对文件进行操作处理,而文件相关的处理无非就是打开文件,读取或者写入内容,最后再是关闭文件。ython中文件常用的IO操作有以下几个:

Function Operation open 打开 read 读取 write 写入 close 关闭 readline 行读取 readlines 多行读取 seek 文件指针操作 tell 指针位置

2 打开操作

文件的打开操作是对文件进行操作的第一步,Python中提供open函数,open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None),open 函数是打开一个文件,返回以文件对象(l流对象)和文件描述符。打开文件失败,则返回异常。

2.1 open函数基本使用

创建一个文件test,然后打开它,用完关闭。


1 f = open("test")    # file对象
2 # windows <_io.TextIOWrapper name='test' mode='r' encoding='cp936'>
3 # linux <_io.TextIOWrapper name='test' mode='r' encoding='UTF-8'>
4 print(f.read())    # 读取文件
5 f.close()    # 关闭文件

View Code

文件操作找那个,最常用的操作就是读和写。文件访问的模式有两种:文本模式和二进制模式。不同模式下,操作函数不尽相同,表现的结果也不一样。

2.2 open函数的参数

2.2.1 file

open函数中的file文件是指定要打开或者要创建的文件名,如果不指定路径,默认是当前路径。

2.2.3 mode模式

open函数中提供mode参数,可以控制是以什么方式打开文件的,不同的模式适用不同场景下对文件的操作。以下是打开文件的模式以及其对应的作用:

Description Meaning r 缺省的,表示只读打开 w 只写打开 x 创建并写入一个新文件 a 写入打开,如果文件存在,则追加 b 二进制模式 t 缺省的,文本模式 + 读写打开一个文件。给原来只读、只写方式打开提供缺失的读或者写能力

在2.1的例子中,打开test文件时没有指定mode参数,那么就是默认以文本打开模式并且是以只读模式打开test文件。

  • r模式

open默认是只读模式r打开已经存在的文件,如果文件不存在,抛出FileNotFoundErro异常。只读打开文件,如果使用write方法,会抛出异常。

  • w模式

如果mode后是w描述符,表示只写方式打开文件,如果读取则抛出异常。如果文件不存在,则直接创建文件,如果文件存在,则清空文件内容。

  • x模式

x模式下如果文件不存在,创建文件,并以只写方式打开文件;文件存在时,抛出FileExistsError异常。

  • a模式

a模式下,文件存在,只写模式打开,追加内容;文件不存在,则创建后,只写模式打开文件,追加内容。

  • 文本模式t

字符流,将文件的字节按照某种字符编码理解,按照字符操作。open的默认mode是rt。

  • 二进制模式b

字节流,将文本按照字节理解,与字符编码无关。二进制模式操作是,字节操作使用bytes类型。

  • +模式

为r、w、a、x提供确实的读写功能。但是,获取文件对象依旧按照r、w、a、x。+不能单独使用,可以认为它是为前面的模式字符做增强功能的。

2.2.4 buffering: 缓冲区

Python在处理文件时,是在内存中对文件进行处理。当给文件中写入内容是,不是立即将内容写入磁盘中,而是先写入内存中,存入缓冲区中待缓冲区满了或者在关闭文件之前,将内存中的内容写入磁盘中。

缓冲区是一个内存空间,一般来说是一个FIFO队列,到缓冲区满了或者达到阈值时数据才会flush到磁盘。flush函数是将缓冲区数据写入磁盘,close()关闭前会调用flush函数。io.DEFAULT_BUFFER_SIZE缺省缓冲区大小,单位是字节,默认是4096或者8192。

open函数中的buffering参数,用-1表示使用缺省大小的buffer。如果是二进制模式,使用io.DEFAULT_BUFFER_SIZE值;如果是文本模式,如果是是终端设备,是行缓方式,如果不是则使用二进制模式的策略。

  • 0只在二进制模式使用,表示关buffer
  • 1只在文本模式使用,表示使用行缓冲。意思就是见到换行符就flush
  • 大于1用于指定buffer的大小

1、二进制下的例子


 1 import io
 2 
 3 f = open('test4', 'w+b')
 4 print(io.DEFAULT_BUFFER_SIZE)
 5 f.write('baidu.com'.encode())
 6 # cat test4
 7 f.seek(0)
 8 # cat test4
 9 f.write('www.baidu.com'.encode())
10 f.flush()
11 f.close()
12 
13 f = open('test4', 'w+b', 4)
14 f.write(b'dab')
15 # cat test4
16 f.write(b'ric')
17 # cat test4
18 f.close

View Code

2、文本模式下


 1 # buffering=1,使用行缓冲
 2 f = open('test4', 'w+', 1)
 3 f.write('dab')    # cat test4
 4 f.write('dabric'*4)    # cat test4
 5 f.write('\n')    # cat test4
 6 f.write('Hello\nPython')    # cat test4
 7 f.close
 8 
 9 # buffering>1,使用指定大小的缓冲区
10 f = open('test4', 'w+', 15)
11 f.write('dab')    # cat test4
12 f.write('ric')    # cat test4
13 f.write('Hello\n')    # cat test4
14 f.write('\nPython')    # cat test4
15 f.write('a' * (io.DEFAULT_BUFFER_SIZE - 20))    # 设置为大于1没什么用
16 f.write('\nwww.baidu.com/python')
17 f.close

View Code

buffering=0,这时一种特殊的二进制模式,不需要内存的buffer,可以看做是一个FIFO的文件。


1 f = open('test4', 'wb+', 0)
2 f.write(b'd')    # cat test4
3 f.write(b'a')    # cat test4
4 f.write(b'b')    # cat test4
5 f.write(b'dabric'*4)    # cat test4
6 f.write(b'\n')    # cat test4
7 f.write(b'Hello\nPython')    # cat test4
8 f.close

View Code

buffering为不同值下多代表的含义总结如下表:

buffering Introduction buffering=-1 t和b都是io.DEFAULT_BUFFER_SIZE buffering=0

b关闭缓冲区

t不支持

buffering=1

b就1个字节

t行缓冲,遇到换行读才flush

buffering>1

b模式表示行缓冲大小。缓冲区的值可以超过io.DEFAULT_BUFFER_SIZE,

直到设定的值超出后才把缓冲区flush

t模式,是io.DEFAULT_BUFFER_SIZE,flush完后把当前字符串也写入磁盘

似乎看起来很玛法,一般来说,只需记得以下几点:

  • 文本模式,一般都使用默认缓冲区大小
  • 二进制模式,是一个个字节的操作,可以指定buffer的大小
  • 一般来说,默认缓冲区大小是个比较好的选择,除非明确知道,否则不调整它
  • 一般编程中,明确知道需要写磁盘了,都会手动调用一次flush,而不是等到自定flush或者close的时候

2.2.5 encoding: 编码,仅文本模式使用

文件在磁盘中的存储是以字节形式存储的,如果要讲文件显示在屏幕上的话,就要对其进行解码,反过来写入时就要对其进行编码。Python中的open函数会在读取文件时做必要的解码,以文本模式写入文件时还会做必要的编码,所以在对文件调用读取或者是写入操作都是字符串对象。

encoding参数指定编码的格式,None标识使用缺省编码,依赖操作系统。windows下缺省GBK,Linux下缺省UTF-8。在对文件的读取和写入操作时要保证编码格式的一致,如果使用默认的编码格式的话,在不同的操作系统中可能会产生乱码的现象,如下:


1 >>> open('cafe.txt', 'w', encoding='utf_8').write('café')
2 4 
3 >>> open('cafe.txt').read()
4 'café'

View Code

写入时文件指定UTF-8编码,但是读取文件时没有那么做。有可能在对文件进行读取时是在windows环境下,那么windows环境下使用的默认编码集为GBK,于是就会产生乱码现在。解决办法是在读取操作之前,打开文件制定编码格式为UTF-8即可。

2.2.6 其他参数

  • errors

errors参数标识什么样的编码错误将被捕获。一般情况下,None和strict表示有编码错误将抛出ValueError异常;ingore标识忽略编码错误。

  • newline

newline参数表示在文本模式中的换行的转换。可以为None、''空串、"\r"、"\n"、"\r\n"。

读时,None表示"\r"、"\n"、"\r\n"都被转换为'\n';''表示不会自动转换通用换行符;其它合法字符表示换行符就是制定字符,就会按照制定字符分行。

写时,None表示'\n'都会被替换为系统缺省分隔符os,linesep;'\n'或''表示'\n'不替换;其它合法字符表示'\n'会被替换为指定的字符。


1 f = open('o:/test', 'w')
2 f.write('python\rwww.python.org\nwww.baidu.com\r\npython3')
3 f.close()
4 
5 newlines = [None, '', '\n', '\r\n']
6 for nl in newlines:
7     f = open('o:/test', 'r+', newline=nl)    # q缺省替换所有换行符
8     print(f.readlines())
9     f.close

View Code
  • closefd

关闭文件描述符,True表示关闭它。False会在文件关闭后保持这个描述符。fileobj.fileno()查看。

3 读取操作

3.1 read函数

read函数读取文件时,将整个文件中的内容读取到内存中,对于小文件的读取可以使用read,其不适用大文件的读取。read函数中的size参数表示读取的多少个字符或字节;负数或None表述读取到EOF。


 1 f = open('o:/test4', 'r+', 0)
 2 f.write("dabric")
 3 f.write('\n')
 4 f.write('你好')
 5 f.seek(0)
 6 f.read(7)
 7 f.close
 8 
 9 # 二进制
10 f = open('test4', 'rb+')
11 f.read(7)
12 f.read(1)
13 f.close()

View Code

3.2 行读取

readline函数表示一行行读取文件内容。size设置一个能读取行内几个字符或字节。

readlines函数表述读取所有行的列表。指定hint则返回指定的行数。


1 # 按行迭代
2 f = open('test')    # 返回可迭代对象
3 
4 for line in f:
5     print(line)
6 
7 f.close()

View Code

4 写入操作

写入操作在前面的代码中多多少少都使用过,下面具体看下写入操作的函数。

write(s),函数把字符串s写入到文件中并返回字符的个数;

writelines(lines),将字符串列表写入文件。


1 f = open('test', 'w+')
2 
3 lines = ['abc', '123\n', 'dabric']    # 提供换行符
4 f.writelines(lines)
5 
6 f.seek(0)
7 print(f.read())
8 f.close()

View Code

5 文件指针

文件是通过文件指针来记录文件当前指向的字节位置,我们可以通过控制文件指针,来指向指定的字节位置。在模式为r的情况下,文件指针指向起始0位置,表示文件开头;在模式为a的情况下,文件指针指向EOF,表示文件末尾,所以a模式被称为追加模式。Python中提供tell函数来显示文件指针当前的位置。

5.1 文件指针操作

Python提供seek(offset[, whence])函数来系统文件指针位置。其中offset表示变异多少字节,whence表示从哪里开始。

在文本模式下,whence的取值:

  • whence 0 缺省值,表示从文件头开始,offset只能为正整数
  • whence 1 表示从当前位置,offset只能接受0
  • whence 2 表示从EOF开始,offset只能接受0

 1 # 文本模式
 2 f = open('test4', 'r+')
 3 f.tell()    # 起始
 4 f.read()
 5 f.tell()    # EOF
 6 f.seek(0)    # 起始
 7 f.read()
 8 f.seek(2, 0)
 9 f.read()
10 f.seek(2, 0)
11 f.seek(2, 1)    # offset必须为0
12 f.seek(2, 2)    # offset必须为0
13 f.close()

View Code

文本模式支持从开头向后偏移的方式。whence为1表示从当前位置开始偏移,但是只支持偏移0,相当于原地不动,所以没有什么用;whence为2表示从EOF开始,只支持偏移0,相当于移动文件指针到EOF。seek函数时按照字节偏移的。

在二进制模式下,whence的取值:

  • whence 0 缺省值,表示从文件头开始,offset只能为正整数
  • whence 1 表示从当前位置,offset可正可负
  • whence 2 表示从EOF开始,offset可正可负

 1 # 二进制模式
 2 f = open('test4', 'rb+')
 3 f.tell()    # 起始
 4 f.read()
 5 f.tell()    # EOF
 6 f.write(b'abc')
 7 f.seek(0)    # 起始
 8 f.seek(2, 1)    # 从当前指针开始,向后偏移2个字节
 9 f.read()
10 f.seek(-2, 1)    # 从当前指针开始,向前偏移2个字节
11 
12 f.seek(2, 2)    # 从EOF开始,向后便宜2个字节
13 f.seek(0)
14 f.seek(-2, 2)    # 从EOF开始,向前偏移2个字节
15 f.read()
16 
17 f.seek(-20, 2)    # OSError
18 f.close()

View Code

二进制模式下支持任意起点的偏移,从头、从尾、从中间位置开始的偏移。向后seek可以超界,但是向前seek的时候,不能超界,否则抛出异常。

6 上下文管理

在每次打开使用文件结束后,都要使用close函数关闭文件对象,有时候在编程时难免会忘记使用close函数对打开的文件关闭,这样会导致该文件在其他地方不能使用的可能。Python提供一种上下文管理机制,使用它后在文件使用完后会自动关闭文件对象。

使用with...as关键字,在with语句执行完的时候,会自动关闭文件对象。注意,上下文管理的语句块并不会开启新的作用域。


1 with open('test') as f:
2     f.write("abc")    # 文件只读,写入失败
3 
4 # 测试f是否关闭
5 f.close    # f的作用域

View Code

另一种写法;


1 f1 = open('test')
2 with f1:
3     f1.write('abc')    # 文件只读,写入失败
4 
5 # 测试f是否关闭
6 f1.close    # f1的作用域

View Code

对于类似于文件对象的IO对象,一般来说都性需要在不使用的时候关闭、注销,以释放资源。IO被打开的时候,会获得一个文件描述符。计算资源是有限的,所以操作系统都会做限制。就是为了保护计算机的资源不要被完全耗尽,计算资源是共享的,不是独占的。一般情况下,除非特别明确的直到资源情况,否则不要提高资源的限制值来解决问题。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK