文件的分类
- 文本文件:储存的是常规字符串文件,通常以’\n’作为每行的结尾。(常规字符串指的是其他编辑器可以直接编辑,且人类可以直接阅读的文本,如英文字母、汉字、数字字符串)
- 二进制文件: 二进制文件把对象内容以字节串(bytes)进行存储,无法用记事本或其他普通字处理软件直接进行编辑,通常也无法被人类直接阅读和理解,需要使用专门的软件进行解码后读取、显示、修改或执行。常见的如图形图像文件、音视频文件、可执行文件、资源文件、各种数据库文件、各类office文档等都属于二进制文件。
文件操作基本流程
四个主要步骤: 打开。操作,保存,关闭。
内置函数open
open(file, mode='r', buffering=-1, encoding=None, errors=None,newline=None, closefd=True, opener=None)
- file参数指定了被打开的文件名称。
- mode参数指定了打开文件后的处理方式。
- buffering参数指定了读写文件的缓存模式。0表示不缓存,1表示缓存,如大于1则表示缓冲区的大小。默认值是缓存模式。
- encoding参数指定对文本进行编码和解码的方式,只适用于文本模式,可以使用Python支持的任何格式,如GBK、utf8、CP936等等。
文件打开模式
- r: 读模式(默认模式,可省略),如果文件不存在则抛出异常
- w: 写模式,如果文件已存在,先清空原有内容
- x: 写模式,创建新文件,如果文件已存在则抛出异常
- a: 追加模式,不覆盖文件中原有内容
- b: 二进制模式(可与其他模式组合使用)
- t: 文本模式(默认模式,可省略)
- +:读、写模式(可与其他模式组合使用)
- r+:可读可写,若文件不存在,报错;w+: 可读可写,若文件不存在,创建
open函数
如果执行正常,open()函数返回1个文件对象,通过该文件对象可以对文件进行读写操作。如果指定文件不存在、访问权限不够、磁盘空间不足或其他原因导致创建文件对象失败则抛出异常。
当对文件内容操作完以后,一定要关闭文件对象,这样才能保证所做的任何修改都确实被保存到文件中。
f1 = open( 'file1.txt','r' ) # 以读模式打开文件
f1.close()
文件对象属性与常用方法
- close() 把缓冲区的内容写入文件,同时关闭文件,并释放文件对象
- flush() 把缓冲区的内容写入文件,但不关闭文件
- read([size]) 从文本文件中读取size个字符(Python 3.x)的内容作为结果返回,或从二进制文件中读取指定数量的字节并返回,如果省略size则表示读取所有内容
- readline() 从文本文件中读取一行内容作为结果返回
- readlines() 把文本文件中的每行文本作为一个字符串存入列表中,返回该列表
- seek(offset[,whence])把文件指针移动到新的字节位置,offset表示相对于whence的位置。whence为0表示从文件头开始计算,1表示从当前位置开始计算,2表示从文件尾开始计算,默认为0
- tell() 返回文件指针的当前位置
- write(s) 把s的内容写入文件
- writelines(s) 把字符串列表写入文本文件,不添加换行符
上下文管理语句with
在实际开发中,读写文件应优先考虑使用上下文管理语句with,关键字with可以自动管理资源,不论因为什么原因(哪怕是代码引发了异常)跳出with块,总能保证文件被正确关闭,并且可以在代码块执行完毕后自动还原进入该代码块时的上下文,常用于文件操作、数据库连接、网络连接、多线程与多进程同步时的锁对象管理等场合。
with open(filename, mode, encoding) as fp:
操作示例
向文本文件中写入内容,然后再读出
s ='Hello world\n我永远喜欢鹿乃\nmikudaisuki\n'
with open('sample.txt','w') as fp: #默认使用cp936编码
fp.write(s)
with open('sample.txt') as fp: #默认使用cp936编码
print(fp.read())
遍历并输出文本文件的所有行内容。
with open('sample.txt') as fp: #假设文件采用CP936编码
for line in fp: #文件对象可以直接迭代
print(line)
假设文件data.txt中有若干整数,每行一个整数,编写程序读取所有整数,将其按降序排序后再写入文本文件data_asc.txt中。
with open('data.txt','r') as fp:
data = fp.readlines() #读取所有行,存入列表
data = [int(item) for item in data] #列表推导式,转换为数字
data.sort(reverse=True) #降序排序
data = [str(item)+'\n' for item in data] #将结果转换为字符串
with open('data_desc.txt','w') as fp: #将结果写入文件
fp.writelines(data)
统计文本文件中最长行的长度和该行的内容。
with open('sample.txt') as fp:
result = [0,'']
for line in fp:
t = len(line)
if t > result[0]:
result = [t, line]
print(result)
二进制文件操作
对于二进制文件,不能使用记事本或其他文本编辑软件直接进行正常读写,也不能通过Python的文件对象直接读取和理解二进制文件的内容。必须正确理解二进制文件结构和序列化规则,然后设计正确的反序列化规则,才能准确地理解二进制文件内容。
所谓序列化,简单地说就是把内存中的数据在不丢失其类型信息的情况下转成二进制形式的过程,对象序列化后的数据经过正确的反序列化过程应该能够准确无误地恢复为原来的对象。
pickle模块
# 写入
import pickle
data = ("胡桃", 2333, [1, 2, 3])
with open('sample_pickle.dat', 'wb') as f:
try:
pickle.dump(len(data), f) #要序列化的对象个数
for item in data:
pickle.dump(item, f) #序列化数据并写入文件
except:
print('写文件异常')
# 读取
with open('sample_pickle.dat','rb') as f:
n = pickle.load(f)
for i in range(n):
x = pickle.load(f) #读取并反序列化每个数据
print(x)
struct模块
import struct
sn = struct.pack('if?', 123, 114.514, True)
s = "胡桃我真的好喜欢你啊!"
# 序列化,i表示整数,f表示实数,?表示逻辑值
# i -> i, f -> 114.514 , ? -> True
with open('sample_struct.dat','wb') as f:
f.write(sn)
f.write(s.encode()) #字符串需要编码为字节串再写入文件
读取
with open('sample_struct.dat','rb') as f:
sn = f.read(9)
n, x, b1 = struct.unpack('if?', sn) #使用指定格式反序列化
print('n=',n,'x=',x, 'b1=', b1)
s = f.read(9).decode()
print('s=', s)
shelve模块
写入
import shelve
zhangsan = {'age':38,'sex':'Male','address':'SDIBT'}
lisi = {'age':40,'sex':'Male','qq':'1234567','tel':'7654321'}
with shelve.open('shelve_test.dat') as fp:
fp['zhangsan'] = zhangsan # 像操作字典一样把数据写入文件
fp['lisi'] = lisi
for i in range(5):
fp[str(i)] = str(i)
读取
with shelve.open('shelve_test.dat') as fp:
print(fp['zhangsan']) #读取并显示文件内容
print(fp['zhangsan']['age'])
print(fp['lisi']['qq'])
print(fp['3'])
结果
{'sex': 'Male','address': 'SDIBT','age': 38}
38
1234567
3
marshal模块
写入
import marshal #导入模块
x = [30, 5.0, [1, 2, 3], (4, 5, 6), {'a': 1, 'b': 2, 'c': 3}, {8, 9, 7}]
with open('test.dat', 'wb') as fp: #创建二进制文件
marshal.dump(len(x), fp) #先写入对象个数
for item in x:
marshal.dump(item,fp) #把列表中的对象依次序列化并写入文件
读取
with open('test.dat','rb') as fp: #打开二进制文件
n = marshal.load(fp) #获取对象个数
for i in range(n):
print(marshal.load(fp)) #反序列化,输出结果
结果
30
5.0
[1, 2, 3]
(4, 5, 6)
{'a': 1,
'b': 2,
'c': 3}
{8, 9, 7}
操作Excel文件
使用扩展库openpyxl读写Excel 2007以及更高版本的文件。
import openpyxl
from openpyxl import Workbook
fn = r'f:\test.xlsx' #文件名
wb = Workbook() #创建工作簿
ws = wb.create_sheet(title='你好,世界') #创建工作表
ws['A1'] = '这是第一个单元格' #单元格赋值
ws['B1'] = 3.1415926
wb.save(fn) #保存Excel文件
wb = openpyxl.load_workbook(fn) #打开已有的Excel文件
ws = wb.worksheets[1] #打开指定索引的工作表
print(ws['A1'].value) #读取并输出指定单元格的值ws.append([1,2,3,4,5]) #添加一行数据
ws.merge_cells('F2:F3') #合并单元格
ws['F2'] = "=sum(A2:E2)" #写入公式
for r in range(10,15):
for c in range(3,8):
ws.cell(row=r, column=c, value=r*c) #写入单元格数据
wb.save(fn)
把记事本文件test.txt转换成Excel 2007+文件。假设test.txt文件中第一行为表头,从第二行开始是实际数据,并且表头和数据行中的不同字段信息都是用逗号分隔。
from openpyxl import Workbook
def main(txtFileName):
new_XlsxFileName = txtFileName[:-3] + 'xlsx'
wb = Workbook()
ws = wb.worksheets[0]
with open(txtFileName) as fp:
for line in fp:
line = line.strip().split(',')
ws.append(line)
wb.save(new_XlsxFileName)
main('test.txt')