Python-文件读写

  1. 文件读写
    1. 打开文件
    2. 读文件
    3. 写文件
    4. 关闭文件
    5. 文件指针

文件读写

读写文件之前,必须先打开文件。

打开文件

内置函数open()用于打开文件,函数的返回值是一个文件对象,通过该对象就可以操作文件了。
第一个参数是文件的路径,必须要指定。既可以指定绝对路径也可以指定相对路径
第二个参数是文件的打开方式,默认值是'r',表示以只读方式打开。
其他参数都是带默认值的,可以参考官方文档。

文件的打开方式 说明 备注
‘r’ 以只读方式打开,只能读文件 文件的默认打开方式
如果文件不存在,则抛出异常FileFoundError
‘w’ 以只写方式打开,只能写文件 如果文件存在,则清空文件
如果文件不存在,则创建文件
‘a’ 以追加方式打开,只能写文件 如果文件存在,则从文件末尾开始写
如果文件不存在,则创建文件
‘x’ 以只写方式打开,只能写文件 如果文件存在,则抛出异常FileExistsError
如果文件不存在,则创建文件
‘+’ 以读写方式打开,可以读写文件 不能单独使用,只能添加到其他打开方式的后面
‘r+’:参见’r’的备注
‘w+’:参见’w’的备注
‘a+’:参见’a’的备注
‘x+’:参见’x’的备注
‘t’ 以文本方式打开 文件默认打开方式,不能单独使用,只能添加到其他打开方式的后面:
‘rt’,’wt’,’at’,’rt+’,’wt+’,’at+’,’xt+’
‘b’ 以二进制方式打开 例如:打开图片不能单独使用,只能添加到其他打开方式的后面:
‘rb’,’wb’,’ab’,’xb’,’rb+’,’wb+’,’ab+’,’xb+’

读文件

可以调用内置函数open()并以只读方式或读写方式打开文件。返回的文件对象有三个用于读文件的方法:
1、read([size]),如果不关闭文件,每次调用此方法,将从上一次调用此方法的地方继续读取文件。

  • 如果不传参数,读到文件尾部。
  • 如果传入参数size,用于指定字节数,
    当指定的字节数小于读到文件尾的字节数时,读取指定的字节数;
    当指定的字节数大于读到文件尾的字节数时,或当指定的字节数小于0时,读取到文件尾部;
>>> fh = open('a.txt', 'r')
>>> fh.read()
'1234567890\nqwertyuiop\nasdfghjkl\nzxcvbnm\n'

>>> fh.read()   # 由于已经读到了文件尾部且没有关闭文件,再次调用将从尾部读取,没有读取到数据
''
>>> fh.close()
>>> fh = open('a.txt', 'r')   
>>> fh.read(-2)     # 传入负数,将直接读取到文件尾部
'1234567890\nqwertyuiop\nasdfghjkl\nzxcvbnm\n'
>>> fh.close()

注意:如果文件较大,使用read()读取全部文件会导致内存占用较大,因此,最好多次调用read([size]),指定的size不要超过默认缓冲区的大小,否则,可能并不能读取到指定的字节数。
默认缓冲区大小通过标准库中io模块的DEFAULT_BUFFER_SIZE获取

>>> import io
>>> io.DEFAULT_BUFFER_SIZE
8192

2、readline([size]),如果不关闭文件,每次调用此方法,将从上一次调用此方法的地方继续读取文件。

  • 如果不传参数,读到行尾。
  • 如果传入参数size,用于指定字节数,
    当指定的字节数小于读到行尾的字节数时,读取指定的字节数;
    当指定的字节数大于读到行尾的字节数时,或当指定的字节数小于0时,读取到行尾部;
    总之,最多读到行尾。
# 如果不传参数,读到行尾
>>> fh = open('a.txt', 'r')
>>> fh.readline()
'1234567890\n'
>>> fh.readline()
'qwertyuiop\n'
>>> fh.readline()
'asdfghjkl\n'
>>> fh.readline()
'zxcvbnm\n'
>>> fh.readline()
''
>>> fh.close()
# 当指定的字节数小于读到行尾的字节数时,读取指定的字节数
>>> fh = open('a.txt', 'r')
>>> fh.readline(7)
'1234567'
>>> fh.readline(7)      # 当指定的字节数大于读到行尾的字节数时,或当指定的字节数小于0时,读取到行尾部
'890\n'
>>> fh.readline(7)
'qwertyu'
>>> fh.readline(7)
'iop\n'
>>> fh.readline(7)
'asdfghj'
>>> fh.readline(7)
'kl\n'
>>> fh.readline(7)
'zxcvbnm'
>>> fh.readline(7)
'\n'
>>> fh.readline(7)
''
>>> fh.close()
# 当指定的字节数大于读到行尾的字节数时,或当指定的字节数小于0时,读取到行尾部
>>> fh.close()
>>> fh = open('a.txt', 'r')
>>> fh.readline(20)
'1234567890\n'
>>> fh.readline(20)
'qwertyuiop\n'
>>> fh.readline(20)
'asdfghjkl\n'
>>> fh.readline(20)
'zxcvbnm\n'
>>> fh.readline(20)
''
>>> fh.close()

3、readlines([size])

  • 如果不传参数,读到文件尾部,返回每一行组成的列表。
  • 如果传入参数,size用于指定字节数,
    当指定的字节数小于读到文件尾的字节数时,一直读取到最后一个字符所在的行尾;
    当指定的字节数大于读到文件尾的字节数时,或当指定的字节数小于0时,读取到文件尾部;
# 如果不传参数,读到文件尾部,返回每一行组成的列表
>>> fh = open('a.txt', 'r')
>>> fh.readlines()
['1234567890\n', 'qwertyuiop\n', 'asdfghjkl\n', 'zxcvbnm\n']
>>>
>>> fh.readlines()
[]
>>> fh.close()
# 当指定的字节数小于读到文件尾的字节数时,一直读取到最后一个字符所在的行尾
>>> fh = open('a.txt', 'r')
>>>
>>> fh.readlines(5)
['1234567890\n']
>>> fh.readlines(5)
['qwertyuiop\n']
>>> fh.readlines(5)
['asdfghjkl\n']
>>> fh.readlines(5)
['zxcvbnm\n']
>>> fh.readlines(5)
[]
>>> fh.close()
# 当指定的字节数大于读到文件尾的字节数时,或当指定的字节数小于0时,读取到文件尾部
>>> fh = open('a.txt', 'r')
>>> fh.readlines(-5)
['1234567890\n', 'qwertyuiop\n', 'asdfghjkl\n', 'zxcvbnm\n']
>>> fh.close()

写文件

写文件之前,必须打开文件。
可以调用内置函数open()并且以只写方式、追加方式、读写方式打开文件。这样,返回的文件对象有两个用于写文件的方法:
1、write(text)

  • 用于将指定的字符串写入到文件中。方法的返回值是写入的字符数,即指定的字符串的长度。
>>> fh = open('a.txt', 'w')  
>>> fh.write('hello')
5
>>> fh.write(' python')
7
>>> fh.close()
>>>

2、writelines(seq)

  • 用于将指定的字符串序列写入到文件中
>>> fh = open('a.txt', 'w')
>>> fh.writelines(['qwe\n', 'asd\n', 'zxc\n'])
>>> fh.close()

调用这个两个方法后,会将指定的字符串写入到缓存中,手动调用方法flush()或者close(),或者当写入的数据量大于等于缓存的容量时,缓存中的字符串才会被写入文件中

关闭文件

文件在使用完毕后必须要关闭,这是因为文件对象会占用操作系统的资源,并且操作系统在某一时刻所能打开的文件数量也是有限的。

读文件或写文件时都有可能发生异常,从而导致方法close()不会被调用,为了保证方法close()总能被调用,可以把读文件或写文件的操作放在try语句块中,把方法close()的调用放在finally中,
伪代码如下:

try:
    读文件或写文件
finally:
    调用方法close()关闭文件

由于文件对象实现了特殊方法__enter__()__exit__(),所以文件对象可以作为上下文管理器。其中特殊方法__enter__()用于返回打开的文件对象,特殊方法__exit__()中关闭打开的文件,因此,上面的伪代码可以使用with语句实现:

with 打开文件 as file:
    读写文件

文件指针

任何文件对象都有一个文件指针,用于指向文件中的某个位置。
读写文件时,是从文件指针的当前位置开始读写的,在读写过程中,文件指针会随之往后移动。

打开文件后,文件指针的位置
以追加(’a’)方式打开文件后,文件指针指向文件的结尾位置;以其他方式打开文件后,文件指针指向文件的起始位置。
调用文件对象的方法tell(),返回文件指针的当前位置。

>>> fh = open('a.txt', 'r')
>>> fh.tell()
0
>>> fh.close()
>>> fh = open('a.txt', 'a')  # 追加方式文件指针在文件的末尾
>>>
>>> fh.tell()
11
>>>
>>> fh.close()

在读写文件时,文件指针移动过程

>>> fh = open('a.txt', 'r')
>>> fh.tell()        # 起始位置是0
0
>>> fh.read(3)
'qwe'
>>>
>>> fh.tell()
3
>>> fh.read(5)
'\nasd\n'
>>> fh.tell()
8
>>> fh.close()

自由移动文件指针
可以调用文件对象的方法seek(),将文件指针自由移动到参数指定的位置
语法格式:

seek(offset, [whence])

参数offset表示偏移量,可以为正数和负数,正数表示往后偏移,负数表示往前偏移。
参数whence是可选的,表示相对偏移位置,有三种取值:
1、os.SEEK_SET:相对文件的起始位置,值为0,默认值
2、os.SEEK_CUR:相对文件的当前位置,值为1
3、os.SEEK_END:相对文件的结尾位置,值为2

只有以二进制方式打开的文件,才能支持上述三种方式,如果以文本方式打开的文件,只支持相对文件的起始位置。
如果要使用os.SEEK_SET、os.SEEK_CUR、os.SEEK_END,需要导入os模块,但是这三个属性其实就是相当于数值0、1、2
os.SEEK_SET == 0
os.SEEK_CUR == 1
os.SEEK_END == 2

>>> fh = open('a.txt', 'r')   # 因为是以文本方式打开的,因此只支持相对文件的起始位置
>>> fh.tell()
0
>>> fh.seek(5)              # 从文件的起始位置,偏移5个指针
5
>>> fh.tell()
5
>>> fh.read(2)
'56'
>>>
>>> fh.seek(0)
0
>>>
>>> fh.tell()          # 从文件的起始位置,偏移0个指针,回到文件的起始位置
0
>>> fh.read(2)
'01'

>>> fh.seek(-5, 2)                   # 因为是以文本方式打开的,因此只支持相对文件的起始位置,另外两种方式就会抛出异常
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
io.UnsupportedOperation: can't do nonzero end-relative seeks
>>> fh = open('a.txt', 'rb')
>>> fh.tell()
0
>>> fh.seek(-2, 2)
20
>>> fh.tell()
20
>>>
>>> fh.read()
b'j\n'
>>> fh.close()

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 289211569@qq.com