python 读写文件
读写文件
关注公众号“轻松学编程”了解更多。
读写文件是最常见的IO操作,python内置了读写文件的函数,用法和c是兼容的.
读写文件前,我们必须了解一下,在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘,所以读写文件就是请求操作系统打开一个文件对象(文件描述),然后,通过操作系统提供的接口从这个文件对象中读取数据(读文件),或者把数据写入这个文件对象(写文件).
1、读文件
要以读文件的模式打开一个文件对象,使用python内置的open()函数,传入文件名和标识符:
f = open("t1.txt","r",encoding="utf-8")
标识符’r’表示读。
如果文件不存在,open()函数就会抛出一个IOError的错误,并且会给出详细的错误码和信息,告诉你文件不存在。
f = open("t122.txt","r",encoding="utf-8")
Traceback (most recent call last):
File "D:/Learn/python/day14/test.py", line 1, in <module>
f = open("t122.txt","r",encoding="utf-8")
FileNotFoundError: [Errno 2] No such file or directory: 't122.txt'
如果文件打开成功,接下来,调用read()方法可以一次性读取文件的全部内容,python把内容读取到内存,用一个str对象表示。
print(f.read())
输出:
hello world!
最后一步调用close()方法关闭文件,文件使用完毕之后必须关闭,因为文件对象会占用操作系统的资源,并且操作系统同一时间能打开的文件数量也是有限制的。
f.close()
f = open(r"文件地址","读取方式",encoding="utf-8")
"r":以只读方式
encoding:读取的编码格式
f.read() :一次性读取文件全部内容
f.close():关闭流
r"文件地址":不让转义字符“\”起作用
由于文件读写都有可能产生IOError,一旦出错,后面的f.close()就不会调用,所以,为了保证文件不管是否执行出错都能够正确的关闭文件,我们可以使用try … finally来实现.
try:
f = open("t1.txt", "r", encoding="utf-8")
print(f.read())
finally:
if f:
f.close()
但是每次都这么写实在太繁琐,所以,引入了with语句来自动帮我们调用close()方法:
with open("t1.txt", "r", encoding="utf-8") as f:
print(f.read())
这和前面的try…finally是一样的,但是代码更加简洁,并且不必调用f.close()方法。
注意: 使用read()会一次性读取文件的全部内容,如果你的文件特别大,比如说有5G,那么你的内存就爆了,所以,为了保险起见,我们可以反复调用read(size)方法,每次最多读取size个字节内容,另外调用readline()可以每次读取一行内容,调用readlines()一次性读取所有的内容,并按行返回list,因此,要根据需要决定怎么调用。
如果文件很小,read()一次读取最方便,如果不能确定文件大小,反复调用read(size)比较保险,如果是配置文件,调用readlines()最方便。
for line in f.readlines():
#把末尾的'\n'删掉
print(line.strip())
2、二进制文件
前面讲的默认都是读取文本文件,并且是UTF-8编码的文本文件,要读取二进制文件,比如图片,视频等等,用’rb’模式打开文件即可:
f = open("tigle.jpg", "rb")
print(f.read())
b'\xff\xd8\xff\xe1\x00\x18Exif\x00\x00...' # 十六进制表示的字节
3、字符编码
要读取非UTF-8编码的文本文件,需要给open()函数传入encoding参数,例如,读取GBK编码的文件:
f = open('/user/demo/gbk.txt','r',encoding = 'gbk')
f.read()
'测试'
遇到有些编码不规范的文件,你可能遇到UnicodeDecodeError,因为在文本文件中可能夹杂了一些非法编码的字符,遇到这种情况,open()函数还接收一个error参数,表示如果遇到编码错误之后如何处理,最简单的办法就是直接忽略。
f = open('/users/demo/gbk.txt','r',encoding = 'gbk',errors = 'ignore')
4、写文件
写文件和读文件都是一样的,唯一的区别就是调用open()函数时,传入标识符’w’或者’wb’表示写文件或写二进制文件:
f = open("/users/demo/test.txt",'w')
f.write('hello, world!')
f.close()
你可以反复调用write()来写入文件,但是务必要调用f.close()来关闭文件.
当我们写入文件时,操作系统往往不会立刻把数据写入磁盘,而是放到内存缓存起来,空闲的时候再慢慢写入,只有调用close()方法时,操作系统才保证把没有写入的数据全部写入磁盘,忘记调用close()的后果是数据可能只写了一部分到磁盘,剩余的丢失了,所以,还是使用with语句来的保险:
with open('/users/demo/test.txt', 'w') as f:
f.write('hello, world')
要写入特定编码的文本文件,请给open()函数传入encoding参数,将字符串自动转成指定编码。
以’w’模式写入文件时,如果文件已经存在,直接覆盖(相当于删掉后新写入一个文件),如果我们希望追加到文件的末尾怎么办?可以传入’a’以追加模式写入。
with open('/users/demo/test.txt', 'a') as f:
f.write('hello, world')
5、StringIO
很多时候,数据读写不一定是文件,也可以在内存读写.
stirngIO顾名思义就是在内存中读写str。
要把str写入StringIO,我们需要先创建一个StringIO,然后,像文件一样写入即可:
from io import StringIO
f = StringIO()
f.write("hello")
f.write(" ")
f.write('world')
#获取写入后的str
print(f.getvalue())
输出:
hello world
要读取StringIO,可以用一个str初始化StringIO,然后,像读文件一样读取:
from io import StringIO
f = StringIO("Hello\nHi\nGoodBye!")
while True:
s = f.readline()
if s == '':
break
# 去掉换行符
print(s.strip())
输出:
Hello
Hi
GoodBye!
6、BytesIO
StringIO操作的只能是str,如果要操作二进制数据,就需要使用BytesIO。
BytesIO实现了在内存中读写bytes,我们创建一个BytesIO,然后写入一些bytes:
from io import BytesIO
f = BytesIO()
f.write("中文".encode('utf-8'))
print(f.getvalue())
输出:
b'\xe4\xb8\xad\xe6\x96\x87'
注意:写入的不是str,而是经过UTF-8编码的bytes。
和StringIO类似,可以用一个bytes初始化BytesIO,然后,像读文件一样读取:
from io import BytesIO
f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')
d = f.read()
print(d)
print(d.decode())
输出:
b'\xe4\xb8\xad\xe6\x96\x87'
中文
StringIO和BytesIO是在内存中操作str和bytes的方法,使得读写文件具有一致的接口.
7、序列化
在程序运行的过程中,所有的变量都是在内存中,比如定义一个dict
dict1 = {name:"lili",age:18}
在这里我把name进行修改,改成”leilei“,但是一旦程序结束,变量所占用的内存就会被操作系统全部回收,如果没有把修改的name存到磁盘上,下次name初始化的时候又是”lili“
在这里我们把变量从内存中变成可存储或者传输的过程称之为序列化,在python中叫picking,序列化之后,我们就可以把序列化后的内容写入磁盘,或是通过网络传输到别的机器上。反之,把变量内容从序列化的对象重新读取到内存里称之为反序列化,即unpicking。
python提供了pickle模块来实现序列化。
import pickle
d = dict({"name":"lili","age":18})
#pickle.dumps()方法把任意对象序列化成一个bytes,然后就可以把bytes写入文件
print(pickle.dumps(d))
#把序列化后的对象写入文件
f = open("t1.txt",'wb')
#参数一:要写入的对象, 参数二:写入文件的对象
pickle.dump(d,f)
f.close()
#从文件中读取序列化后的对象
f2 = open("t1.txt","rb")
#pickle.load()反序列化对象
d = pickle.load(f2)
f2.close()
print(d)
print(type(d))
输出:
{'name': 'lili', 'age': 18}
<class 'dict'>
注意:pickle只能用于python,并且不同版本的python彼此都不兼容,因此,只能用pickle保存一些不重要的数据,这样即使不能成功的反序列化也没什么关系。
8、Json
如果我们需要在不同的编程语言之间传递对象,那么我们必须把对象序列化成标准化格式,比如xml,但是更好的方法是json,因为json表现出来就是一个字符串,可以被所有的语言读取,也方便存储到磁盘或者网络传输,json不仅是标准模式,并且速度也比xml更快,还可以在web中读取,非常方便。
JSON类型 | Python类型 |
---|---|
{} | dict |
[] | list |
“string” | str |
1234.56 | int或float |
true/false | True/False |
null | None |
把python的dict对象变成一个json
import json
dict1 = {"name":"lili","age":18}
ji = json.dumps(dict1)
print(type(ji))
with open("dd.txt","w") as f:
json.dump(dict1,f)
with open("dd.txt","r",encoding="utf-8") as f:
du = json.load(f)
print(du)
print(type(du))
输出:
<class 'str'>
{'name': 'lili', 'age': 18}
<class 'dict'>
将一个class对象序列化为json
import json
class Student(object):
def __init__(self, name, age, score):
self.name = name
self.age = age
self.score = score
# 将student对象转换为dict
def student2dict(std):
return {
'name': std.name,
'age': std.age,
'score': std.score
}
s = Student('Bob', 20, 88)
# 参数一:要传入的对象 参数二:将对象转为dict的函数
d = json.dumps(s, default=student2dict)
# 将dict转为对象
def dict2student(d):
return Student(d['name'], d['age'], d['score'])
jsonStr = '{"age": 20, "score": 88, "name": "Bob"}'
# json反序列化为一个对象
# 参数一:json字符串,参数二:dict转为对象的函数
print(json.loads(jsonStr, object_hook=dict2student))
# 写入文件
with open("t1.txt","w") as f:
f.write(d)
#或者直接使用下面的语句
#json.dump(s,f,default=student2dict)
# 读取文件
with open("t1.txt","r",encoding="utf-8") as f:
du = json.load(f,object_hook=dict2student)
print(du)
输出:
<__main__.Student object at 0x000002CA795AA0F0>
<__main__.Student object at 0x000002CA7975B0F0>
9、读写csv文件
1、读csv文件
csv文件本身就是个纯文本文件,这种文件格式经常用来作为不同程序之间的数据交互的格式.
演示:
需求:读取001.scv文件
说明:可以直接打印,然后定义list
import csv
def readCsv(path):
#列表
infoList = []
#以只读的形式打开文件
with open(path, 'r') as f:
#读取文件的内容
allFileInfo = csv.reader(f)
#将获取到的内容逐行追加到列表中
for row in allFileInfo:
infoList.append(row)
return infoList
path = r"C:\Users\xlg\Desktop\001.csv"
info = readCsv(path)
2、写csv文件
演示:
需求:向002.csv文件中写入内容
import csv
#以写的方式打开文件
def writeCsv(path,data):
with open(path,'w',newline='') as f:
writer = csv.writer(f)
for rowData in data:
print("rowData =", rowData)
#按行写入
writer.writerow(rowData)
path = r"C:\Users\xlg\Desktop\002.csv"
writeCsv(path,[[1,2,3],[4,5,6],[7,8,9]])
10、读取pdf文件
pip是一个安装和管理python包的工具
在进行代码演示之前,首先进行安装和pdf相关的工具
a.在cmd中输入以下命令: pip list [作用:列出pip下安装的所有的工具]
b.安装pdfminer3k,继续输入以下命令:pip install pdfminer3k
c.代码演示
import sys
import importlib
importlib.reload(sys)
from pdfminer.pdfparser import PDFParser, PDFDocument
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter #解释器
from pdfminer.converter import PDFPageAggregator #转换器
from pdfminer.layout import LTTextBoxHorizontal, LAParams #布局
from pdfminer.pdfinterp import PDFTextExtractionNotAllowed #是否允许pdf和text转换
def readPDF(path, toPath):
#以二进制形式打开pdf文件
f = open(path, "rb")
#创建一个pdf文档分析器
parser = PDFParser(f)
#创建pdf文档
pdfFile = PDFDocument()
#链接分析器与文档对象
parser.set_document(pdfFile)
pdfFile.set_parser(parser)
#提供初始化密码
pdfFile.initialize()
#检测文档是否提供txt转换
if not pdfFile.is_extractable:
raise PDFTextExtractionNotAllowed
else:
#解析数据
#数据管理器
manager = PDFResourceManager()
#创建一个PDF设备对象
laparams = LAParams()
device = PDFPageAggregator(manager, laparams=laparams)
#解释器对象
interpreter = PDFPageInterpreter(manager, device)
#开始循环处理,每次处理一页
for page in pdfFile.get_pages():
interpreter.process_page(page)
layout = device.get_result()
for x in layout:
if (isinstance(x, LTTextBoxHorizontal)):
with open(toPath, "a") as f:
str = x.get_text()
#print(str)
f.write(str+"\n")
path = r"0319开始.pdf"
toPath = r"n.txt"
readPDF(path, toPath)
后记
【后记】为了让大家能够轻松学编程,我创建了一个公众号【轻松学编程】,里面有让你快速学会编程的文章,当然也有一些干货提高你的编程水平,也有一些编程项目适合做一些课程设计等课题。
也可加我微信【1257309054】,拉你进群,大家一起交流学习。
如果文章对您有帮助,请我喝杯咖啡吧!
公众号
关注我,我们一起成长~~