Python之文本操作
文本文件
文本文件是一种典型的顺序文件,其文件的逻辑结构又属于流式文件。文本文件是指以 ASCII 码方式(也称文本方式)存储的文件,更确切地说,英文、数字等字符存储的是 ASCII 码,而汉字存储的是机内码。
文本文件中除了存储文件有效字符信息(包括能用 ASCII 码字符表示的回车、换行等信息)外,不能存储其他任何信息,比如图片、视频等等。我们常见的 txt 文件就是文本文件。
Python 的 open 方法用于打开一个文件,并返回文件对象,在对文件进行处理过程都需要使用到这个函数,如果该文件无法被打开,会抛出异常。
open 方法的语法格式为:
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closed=True, opener=None)
- file:表示要打开的文件路径(相对或者绝对路径);
- mode:表示文件打开模式;
- buffering:用于设置缓冲;
- encoding:用于设置编码格式,一般使用 utf8;
- errors:指明编码和解码错误时怎么样处理,适用于文本模式;
- newline:文本模式之下,控制一行的结束字符;
- closed:传入的 file 参数类型;
- opener:自定义打开文件方式。
文件打开模式
mode 参数的打开模式具体如下表所示:
模式 | 描述 |
---|---|
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。 |
w | 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
w+ | 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
假设现在有一个 test.txt 文件,位于 step1 目录下,我们可以使用下列代码来打开文件:
f = open("step1/test.txt","r",encoding="utf8") # f就是文件对象,一般情况下,只设置这3个参数
关闭文件 close 函数
close() 方法用于关闭一个已打开的文件。关闭后的文件不能再进行读写操作, 否则会触发 ValueError 错误。 close() 方法允许调用多次。
当 file 对象被引用到操作另外一个文件时,Python 会自动关闭之前的 file 对象。 使用 close() 方法关闭文件是一个好的习惯。
f = open("step1/test.txt","r",encoding="utf8")# 进行相关的读写操作之后使用 close 函数关闭文件f.close()
文件对象常用属性
文件对象常用的属性主要有 3 个:
-
closed:如果文件已被关闭返回 True,否则返回 False;
f = open("step/test.txt","r",encoding="utf8")print(f.closed)f.close()print(f.closed)
执行结果:
FalseTrue
-
mode:返回被打开文件的访问模式;
f = open("step/test.txt","r",encoding="utf8")print(f.mode)
执行结果:
r
-
name:返回文件的名称;
f = open("step/test.txt","r",encoding="utf8")print(f.name)
执行结果:
step/test.txt
Python文件之文本文件的随机读写
随机读写
使用 read 等顺序读写函数时,每次都是从每行的第一个字符开始读取,但是,我们不一定每次的需求都是从头开始读取。假设我们有test.txt
文件,内容如下:
hello world
下面我们将介绍随机读取的函数:
-
seek(offset,whence=0):用于移动文件读取指针到指定位置。offset 表示开始的偏移量,也就是代表需要移动偏移的字节数;whence 表示要从哪个位置开始偏移;0 代表从文件开头开始算起,1 代表从当前位置开始算起,2 代表从文件末尾算起。
f = open("test.txt","rb") f.seek(2) # 将读取指针移动到2的位置 print(f.read())# 移动到文件倒数第5个字节,如果要设置whence参数,文件的打开格式必须为二进制模式 f.seek(-5,2) print(f.read()) f.close()
执行结果:
b'llo world'b'world'
-
seekable():如果文件是可搜索的,则 seekable 方法返回 True,否则返回 False。如果文件允许访问文件流(例如 seek 方法),则该文件是可搜索的。
-
tell():返回文件的当前位置,即文件指针当前位置。
f = open("test.txt","r") f.seek(2) print(f.tell()) f.read(1) # 读取一个字节的内容print(f.tell()) # 读取内容也会改变指针的位置f.close()
执行结果:
23
-
truncate([size]):方法用于截断文件并返回截断的字节长度。指定 size 的话,就从文件的开头开始截断指定长度,其余内容删除;不指定 size 就从文件开头开始截断到当前位置,其余内容删除。
f = open("test.txt","r+")print(f.truncate(3))print(f.read())f.close()
执行结果:
3hel
下面是一个对读写文本文件3种方式的总结:
使用Python读/写文本文件
使用Python来读/写文本需要用到“open”这个关键字。它的作用是打开一个文件,并创建一个文件对象。
使用Python打开文件,有两种写法。
第1种方式如下:
f = open('文件路径', '文件操作方式', encoding='utf-8')
对文件进行操作
f.close()
第2种方式,使用Python的上下文管理器:
with open(‘文件路径’, ‘文件操作方式’, encoding=‘utf-8’) as f:
对文件进行操作
第1种方式需要手动关闭文件,但是在程序开发中经常会出现忘记关闭文件的情况。第2种方法不需要手动关闭文件,只要代码退出了缩进,Python就会自动关闭文件
使用Python读文本文件
使用Python打开一个文本文件时,首先要保证这个文件是存在的。在读文件的时候,“文件操作方式”这个参数可以省略,也可以写成“r”,也就是read的首字母。
文件路径可以是绝对路径,也可以是相对路径。如果是绝对路径,Linux和Mac OS不能直接使用“~”表示“home目录”,因为Python不认识“~”这个符号。如果非要使用这个符号,需要使用Python的“os”模块,代码如下:
import os
real_path = os.path.expanduser('~/project/xxx')
使用下面的代码来打开text.txt文件:
with open('text.txt', encoding='utf-8') as f:
通过f来读文件
这里有一个参数“encoding”。这个参数特别有用,它可以在打开文件的时候将文件转换为UTF-8编码格式,从而避免乱码的出现。这个参数只有Python 3有,在Python 2中使用这个参数会报错。如果文件是在Windows中创建的,并且使用UTF-8打开文件出现了乱码,可以把编码格式改为GBK
使用Python写文本文件
使用Python写文件也需要先打开文件,使用如下代码来打开文件:
with open('new.txt', 'w', encoding='utf-8') as f:
通过f来写文件
这里多出来一个参数“w”,w是英文write的首字母,意思是以写的方式打开文件。这个参数除了为“w”外,还可以为“a”。它们的区别在于,如果原来已经有一个new.txt文件了,使用“w”会覆盖原来的文件,导致原来的内容丢失;而使用“a”,则会把新的内容写到原来的文件末尾
二进制文件的读写
我们学习了打开二进制文件的方式,比如rb、wb
等。假设我们现在有一个图片文件test.png
。
with open("test.png","rb") as f: print(f.read()) print(f.read(10)) # 只读取10个字节
执行结果(不同的图片结果不一致):
b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x01\x02\x00\x00\x01X\x08\x06\x00\x00\x00\xb8Z\xf2\xc1\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\....'b'\x89PNG\r\n\x1a\n\x00\x00'
当我们写入二进制文件时,我们只能写入 bytes 类型的数据。
with open("test.png","rb") as f,open("result.png","wb") as fb: data = f.read(10) fb.write(data)
代码运行后,在当前文件夹中就会创建一个result.png
文件,该文件的内容为test.png
的前 10 个字节。
CSV模块读写文件
csv 模块
CSV (Comma Separated Values) 是逗号分隔符文本格式,常用于 Excel 和数据库的导入和导出,Python 标准库的 CSV 模块提供了读取和写入 CSV 格式文件的对象。CSV 以纯文本存储数和文本。文件的每一行就代表一条数据,每条记录包含由逗号分隔一个或多个属性值。
以文本的形式打开 csv 文件如图 1 所示:
图 1
以 Excel 的形式打开 csv 文件如图 2 所示:
图 2
读取 csv 文件
假设我们有一个 test.csv 文件,内容如图 2 所示。
-
以返回列表的形式读取 csv 文件。
import csv # 导入 csv 模块 with open("test.csv","r") as f: result = csv.reader(f) # 返回的是一个迭代器 next(result) # 使用next可以跳过第一行的读取 print(list(result))
执行结果:
[['5.1', '3.5', '1.4', '0.2'], ['4.9', '3', '1.4', '0.2'], ['4.7', '3.2', '1.3', '0.2'], ['4.6', '3.1', '1.5', '0.2'], ['5', '3.6', '1.4', '0.2'], ['5.4', '3.9', '1.7', '0.4'], ['4.6', '3.4', '1.4', '0.3'], ['5', '3.4', '1.5', '0.2'], ['4.4', '2.9', '1.4', '0.2'], ['4.9', '3.1', '1.5', '0.1'], ['5.4', '3.7', '1.5', '0.2'], ['4.8', '3.4', '1.6', '0.2'], ['4.8', '3', '1.4', '0.1'], ['4.3', '3', '1.1', '0.1'], ['5.8', '4', '1.2', '0.2'], ['5.7', '4.4', '1.5', '0.4'], ['5.4', '3.9', '1.3', '0.4'], ['5.1', '3.5', '1.4', '0.3'], ['5.7', '3.8', '1.7', '0.3'], ['5.1', '3.8', '1.5', '0.3'], ['5.4', '3.4', '1.7', '0.2'], ['5.1', '3.7', '1.5', '0.4'], ['4.6', '3.6', '1', '0.2'], ['5.1', '3.3', '1.7', '0.5']]
-
以字典的形式读取 csv 文件。
import csv # 导入 csv 模块 with open("test.csv","r+") as f: # 使用DictReader创建的reader是一个字典对象,遍历后,不包含第一行数据 result = csv.DictReader(f) for x in result: print(x)
执行结果:
OrderedDict([('sepal length (cm)', '5.1'), ('sepal width (cm)', '3.5'), ('petal length (cm)', '1.4'), ('petal width (cm)', '0.2')])OrderedDict([('sepal length (cm)', '4.9'), ('sepal width (cm)', '3'), ('petal length (cm)', '1.4'), ('petal width (cm)', '0.2')])OrderedDict([('sepal length (cm)', '4.7'), ('sepal width (cm)', '3.2'), ('petal length (cm)', '1.3'), ('petal width (cm)', '0.2')])OrderedDict([('sepal length (cm)', '4.6'), ('sepal width (cm)', '3.1'), ('petal length (cm)', '1.5'), ('petal width (cm)', '0.2')])OrderedDict([('sepal length (cm)', '5'), ('sepal width (cm)', '3.6'), ('petal length (cm)', '1.4'), ('petal width (cm)', '0.2')])OrderedDict([('sepal length (cm)', '5.4'), ('sepal width (cm)', '3.9'), ('petal length (cm)', '1.7'), ('petal width (cm)', '0.4')])OrderedDict([('sepal length (cm)', '4.6'), ('sepal width (cm)', '3.4'), ('petal length (cm)', '1.4'), ('petal width (cm)', '0.3')])OrderedDict([('sepal length (cm)', '5'), ('sepal width (cm)', '3.4'), ('petal length (cm)', '1.5'), ('petal width (cm)', '0.2')])OrderedDict([('sepal length (cm)', '4.4'), ('sepal width (cm)', '2.9'), ('petal length (cm)', '1.4'), ('petal width (cm)', '0.2')])OrderedDict([('sepal length (cm)', '4.9'), ('sepal width (cm)', '3.1'), ('petal length (cm)', '1.5'), ('petal width (cm)', '0.1')])OrderedDict([('sepal length (cm)', '5.4'), ('sepal width (cm)', '3.7'), ('petal length (cm)', '1.5'), ('petal width (cm)', '0.2')])OrderedDict([('sepal length (cm)', '4.8'), ('sepal width (cm)', '3.4'), ('petal length (cm)', '1.6'), ('petal width (cm)', '0.2')])OrderedDict([('sepal length (cm)', '4.8'), ('sepal width (cm)', '3'), ('petal length (cm)', '1.4'), ('petal width (cm)', '0.1')])OrderedDict([('sepal length (cm)', '4.3'), ('sepal width (cm)', '3'), ('petal length (cm)', '1.1'), ('petal width (cm)', '0.1')])OrderedDict([('sepal length (cm)', '5.8'), ('sepal width (cm)', '4'), ('petal length (cm)', '1.2'), ('petal width (cm)', '0.2')])OrderedDict([('sepal length (cm)', '5.7'), ('sepal width (cm)', '4.4'), ('petal length (cm)', '1.5'), ('petal width (cm)', '0.4')])OrderedDict([('sepal length (cm)', '5.4'), ('sepal width (cm)', '3.9'), ('petal length (cm)', '1.3'), ('petal width (cm)', '0.4')])OrderedDict([('sepal length (cm)', '5.1'), ('sepal width (cm)', '3.5'), ('petal length (cm)', '1.4'), ('petal width (cm)', '0.3')])OrderedDict([('sepal length (cm)', '5.7'), ('sepal width (cm)', '3.8'), ('petal length (cm)', '1.7'), ('petal width (cm)', '0.3')])OrderedDict([('sepal length (cm)', '5.1'), ('sepal width (cm)', '3.8'), ('petal length (cm)', '1.5'), ('petal width (cm)', '0.3')])OrderedDict([('sepal length (cm)', '5.4'), ('sepal width (cm)', '3.4'), ('petal length (cm)', '1.7'), ('petal width (cm)', '0.2')])OrderedDict([('sepal length (cm)', '5.1'), ('sepal width (cm)', '3.7'), ('petal length (cm)', '1.5'), ('petal width (cm)', '0.4')])OrderedDict([('sepal length (cm)', '4.6'), ('sepal width (cm)', '3.6'), ('petal length (cm)', '1'), ('petal width (cm)', '0.2')])OrderedDict([('sepal length (cm)', '5.1'), ('sepal width (cm)', '3.3'), ('petal length (cm)', '1.7'), ('petal width (cm)', '0.5')])
写入 csv 文件
-
以元组的方式写入。
import csvheaders = ["name","age","height"]values = [("小王",18,178),("小张",20,180),("小李",17,166)] with open("test.csv","w",encoding="utf-8",newline="") as f: writer = csv.writer(f) writer.writerow(headers) # 首先写入第一行 writer.writerows(values) # 写入values
代码运行后,test.csv 的内容变更为:
name,age,height 小王,18,178 小张,20,180 小李,17,166
-
以字典的形式写入。
import csv headers = ["name", "age", "height"] values = [{"name":"小王","age":18,"height":178},{"name":"小王","age":18,"height":178},{"name":"小王","age":18,"height":178}] with open("test.csv","w",encoding="utf-8",newline="") as f: writer = csv.DictWriter(f,headers) # 使用csv.DictWriter()方法,需传入两个参数,第一个为对象,第二个为文件的title writer.writeheader() # 使用此方法,写入表头 writer.writerows(values)
代码运行之后,test.csv 文件的内容为:
name,age,height 小王,18,178 小张,20,180 小李,17,166