python文件操作
为了长期保存数据以便重复使用、修改和共享,必须将数据以文件的形式存储到外部存储介质(如磁盘、U盘、光盘或云盘、网盘、快盘等)中。文件作在各类应用软件的开发中均占有重要的地位。
按照文件中的数据组织形式,将文件分为文本文件和二进制文件。
- 文本文件:储存常规字符,由若干文本行组成,通常以换行符结尾,常规字符串是指记事本或者其他文编编辑器能够正常显示、编辑并且人类能够直接阅读和理解的字符串。如英文字母、汉字、数字字符串。
- 二进制文件:二进制文件把对象内容以字节串
(bytes)
进行储存,通常无法直接被人类阅读和理解,**需要使用专门的软件对其进行解码后读取、显示、修改或执行。常见的有如图形图像文件、音视频文件、可执行文件、资源文件、各种数据库文件、各类office文档
文件对象
Python内置了文件对象,通过open()函数即可以指定模式打开指定文件并创建为文件对象,语法为:
open(file, mode='r',buffering=-1,encoding=None,errors=None,newline=None,closefd=True, opener=None)
-
file
参数指定了被打开的文件名称。 -
mode
参数指定了打开文件后的处理方式。 -
buffering
参数指定了读写文件的缓存模式。0表示不缓存,1表示缓存,如大于1则表示缓冲区的大小。默认值-1表示由系统管理缓存。 -
encoding
参数指定对文本进行编码和解码的方式,只适用于文本模式,可以使用Python支持的任何格式,如GBK、utf8、CP936
等等。
f1 = open('file1.txt', 'r') # 以读模式打开文件
f2 = open('file2.txt', 'w') # 以写模式打开文件
f1.close()#当对文件内容操作完以后,一定要关闭文件对象,这样才能保证所做的任何修改都确实被保存到文件中。
文件打开方式
模式 | 说明 |
---|---|
r | 读模式(默认模式,可省略),如果文件不存在,则就抛出异常 |
w | 写模式,如果文件已经存在,会先清空原有内容 |
x | 写模式 |
a | 追加模式不覆盖原有内容 |
b | 二进制模式(可与其他模式组合使用) |
t | 文本模式(默认模式,可省略) |
+ | 读+写,模式(可与其他模式组合使用) |
文件对象常用方法
方法 | 功能说明 |
---|---|
close() | 把缓冲区的内容写入文件,同时关闭文件,并释放文件对象 |
read([size]) | 从文本文件中读取size 个字符的内容作为结果返回,或从二进制文件中读取指定数量的字节并返回,如果省略size 则表示读取所有内容 |
readable() | 测试当前文件是否可读 |
readline() | 从文本文件中读取一行内容作为结果返回 |
readlines() | 把文本文件中的每行文本作为一个字符串存入列表中,返回该列表,对于大文件会占用较多内存,不建议使用 |
seek(offset[,whence]) | 把文件指针移动到新的字节位置,offset 表示相对于whence 的位置。whence 为0 表示从文件头开始计算,1 表示从当前位置开始计算,2 表示从文件尾开始计算,默认为0 |
write(s) | 把s的内容写入文件 |
writable() | 测试当前文件是否可写 |
writelines(s) | 把字符串列表写入文本文件,不添加换行符 |
with 语句
即使写了关闭文件的代码,也无法保证文件一定能够正常关闭,例如,如果在打开文件之后和关闭文件之前发生了错误导致程序崩溃,这时文件就无法正常关闭。在管理文件对象时推荐使用with关键字,可以有效地避免这个问题。
with语句的用法如下:
with open(filename, mode, encoding) as fp:
#这里写通过文件对象fp读写文件内容的语句
#上下文管理语句with还支持下面的用法:
with open('test.txt', 'r') as src, open('test_new.txt', 'w') as dst:
dst.write(src.read())
seek()方法
seek()方法把文件指针定位到文件中指定字节的位置。读取时遇到无法解码的字符会抛出异常。
seek() 方法语法如下:
fileObject.seek(offset[, whence])
-
offset :文件中读/写指针的位置。
-
whence :(可选)0代表从文件开头开始算起,1代表从当前位置开始算起,2代表从文件末尾算起。
二进制文件
使用pickle
模块读取二进制文件
import pickle
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
n = 1300000000
x = 96.45
b = True
s = 'HELLO'
sn = struct.pack('if?', n, x, b) #序列化
with open('sample_struct.dat', 'wb') as fp:
fp.write(sn) #写入字节串
fp.write(s.encode()) #字符串直接编码为字节串写入
使用struct
模块读取二进制文件
import struct
with open('sample_struct.dat', 'rb') as fp:
sn = fp.read(9)
tu = struct.unpack('if?', sn)
print(tu)
n, x, bl = tu
print('n=', n)
print('x=', x)
print('bl=', bl)
s = fp.read(9).decode()
print('s=', s)
使用shelve序列化
Python标准库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.txt') as fp:
print(fp['zhangsan']) #读取并显示文件内容
print(fp['zhangsan']['age'])
print(fp['lisi']['qq'])
print(fp['3'])
案例
向文本文件中写入内容,然后再读出。
s = "Hello World!\n世界你好!\n"
with open("sample.txt","w") as fp: # 默认使用cp936编码
fp.write(s) #写入文件
with open('sample.txt') as fp: #默认使用cp936编码
print(fp.read()) #读取文件
读取并显示文本文件的前5个字符。
with open('sample.txt', 'r') as f:
s = f.read(5)
print('s=',s)
print('字符串s的长度(字符个数)=', len(s))
读取并显示文本文件所有行。
with open('sample.txt') as fp: #假设文件采用CP936编码
for line in fp: #文件对象可以直接迭代
print(line)
移动文件指针,然后读取并显示文本文件中的内容。
批量修改文本文件编码格式。
#方法一
import os
# 获取当前文件夹中所有记事本文件清单
fns = (fn for fn in os.listdir() if fn.endswith('.txt'))
for fn in fns:
try:
# 首先尝试使用UTF8编码打开并读取文件内容
# 如果失败会抛出异常
with open(fn, encoding='utf8') as fp:
fp.read()
except:
# 以默认的GBK编码读取原文件内容
# 以UTF8编码写入新文件
with open(fn) as fp1:
with open('t.txt', 'w', encoding='utf8') as fp2:
fp2.write(fp1.read())
# 删除原文件,把新文件重命名为原文件
os.remove(fn)
os.rename('t.txt', fn)
#方法二
from os import listdir
fns = (fn for fn in listdir() if fn.endswith('.txt'))
for fn in fns:
with open(fn, 'rb+') as fp:
content = fp.read()
try:
# 尝试使用UTF8解码
content.decode('utf8')
except:
# 使用GBK解码后再使用UTF8编码,写回文件
content = content.decode('gbk').encode('utf8')
fp.seek(0)
fp.write(content)
#方法二
from os import listdir
from chardet import detect
fns = (fn for fn in listdir() if fn.endswith('.txt'))
for fn in fns:
with open(fn, 'rb+') as fp:
content = fp.read()
# 判断编码格式
encoding = detect(content)['encoding']
# 格式转换
content = content.decode(encoding).encode('utf8')
# 写回文件
fp.seek(0)
fp.write(content)
自学笔记,仅供参考
21/11/22