文件读写以及with语句用法

  • 1. 打开文件
  • 2. 读取文件
  • 2.1 按字节或字符读取
  • 2.2 按行读取
  • 3. 写文件
  • 3.1 按字节或字符写
  • 3.2 按行写
  • 4. 游标
  • 5. with语法
  • 5.1 使用with语句打开文件
  • 5.2 什么样的对象可以用with语句实例化


1. 打开文件

Python中提供了一个内置的open()函数,该函数用于打开指定文件。

open(filename [, access_mode][, buffering][, encoding])

其中access_mode表示文件打开模式,共有如下几种:

模式

作用

r

只读模式

w

写模式

a

追加模式

+

读写模式,可与其他模式结合使用,比如r+,w+都代表读写模式。

b

二进制模式,可与其他模式结合使用,比如rb代表二进制只读模式, rb+代表二进制读写模式,ab代表二进制追加模式。

以w和w+模式打开文件后,open()函数会立即清空文件内容,所以使用这两种模式时都无法读取文件内容。

该函数返回一个文件对象,文件对象支持如下常见的属性:

  • file.closed:该属性返回文件是否已经关闭。
  • file.encoding:返回文件的编码方式。
  • file.mode:返回被打开文件的访问模式。
  • file.name:返回文件的名称。

函数参数中的encoding表示使用哪种编码方式开打开文件。

2. 读取文件

Python既可以使用文件对象的方法来读取文件,也可以使用其它模块的函数来读取文件。

2.1 按字节或字符读取

文件对象提供了read()方法来按字节或字符读取文件内容,到底是读取字节还是字符则取决于文件打开的模式。

当以二进制模式来进行文件读取的时候,使用open()来打开文件时,不需要指定encoding参数。

fp = open('test.txt', 'rb')
data = fp.read()
print(type(data), data)
fp.close()
#======output=====
<class 'bytes'> b'hahahaha'

在使用read()方法来读取内容时,返回的也是bytes类型的数据。

当文件读写完毕之后,最好调用close()方法来关闭文件这样可以避免文件泄露。

2.2 按行读取

文件对象提供了两个按行读取的方法:

  • readline():读取文件中的一行,可以指定多少个字符算一行。
  • readlines():读取文件内的所有行,它返回的是一个list,每一行为list中的一个元素。

3. 写文件

3.1 按字节或字符写

文件对象提供了write()方法来按字节或按字符向文件中写内容,与read()方法的使用方法相同需要指定文件的打开模式。

fp = open('test.txt', 'w', encoding='utf-8')
fp.write('hahahaha')
fp.close()

这里我们使用w模式打开文件,默认就是以字符方式进行写操作。

当使用wb模式来打开文件时,就会以字节方式进行写操作,在write中传入的字符串必须是bytes类型。

fp = open('test.txt', 'wb')
fp.write(b'hahahaha')
fp.close()

当然这里的open方法中也不能指定encoding参数。

3.2 按行写

文件对象提供了一个按行写的方法:

  • writelines(lines: List[AnyStr]):这里需要传入的是一个list,里面的每个元素为行中的内容,但是它不会自动换行,如果元素中不加换行符,则默认都将写在一行,如果需要每个元素后换行,则需要在每个元素后加入换行符。

4. 游标

这里的游标指的是一个位置,它是一个相对位置。在使用rw模式打开文件时,这个游标的位置在文件的开头,也就是0,当以a模式来打开文件时,游标会在文件的末尾位置。

它以字节为单位进行移动。

我们可以使用seek()方法来设置游标的位置,它有两个参数,一个为offset,表示游标的偏移量,一个为whence,表示给offset参数的偏移参考,表示要从哪个位置开始偏移;0代表从文件开头开始算起,1代表从当前位置开始算起,2代表从文件末尾算起。

如果要知道当前游标的位置,我们可以使用tell()方法来查看,该方法返回文件游标的位置。

fp = open('test.txt', 'w', encoding='utf-8')
fp.write('hahahaha')
print(fp.tell())
fp.seek(2)
fp.write('gaigaigai')
print(fp.tell())
fp.close()
#=====output=====
8
11

例如我们先写入hahahaha,这时游标的位置为8,此时,我们将游标设置到2,然后继续进行写入操作,写入之后的游标位置为11。

这时打开文件我们可以看到,前面写的部分已经被覆盖掉了,剩下的内容为hagaigaigai

当我们使用读模式打开时,利用seek()方法就可以完成部分重复读的操作了。

5. with语法

5.1 使用with语句打开文件

使用with语句可以避免文件忘记关闭的情况,省去了手动close()文件。

with open("test.txt", 'r', encoding='utf-8') as f:
    lines = f.readlines()
    #其它处理语句

5.2 什么样的对象可以用with语句实例化

要让一个类可以用with语句打开,那么这个类必须实现__enter__方法和__exit__方法。例如:

class Test:
    def __enter__(self):
        print('enter 方法被调用')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("exit 方法被调用")
        print("exc_type :%s" % exc_type)
        print("exc_val :%s" % exc_val)
        print("exc_tb :%s" % exc_tb)

这样我们就可以使用with语句来实例化它:

with Test() as t:
    print(t)
#====output====
enter 方法被调用
None
exit 方法被调用
exc_type :None
exc_val :None
exc_tb :None

我们可以看到,在一开始会调用__enter__方法,在with块结束后会调用__exit__方法,如果with块中的语句出现异常,也会调用__exit__方法。

再回到with open("test.txt", 'r', encoding='utf-8') as f:这个语句,使用该语句后,我们不需要手动关闭文件就是因为__exit__方法,在该方法中它实现了文件的关闭操作,所以我们不用单独使用close()语句来关闭文件对象。