概述
在文件存储中,都是以 字节 为单位进行读写的,本质是 二进制的0和1,为了方便查看,通常用 16进制 展示。
mp3、图片、甚至是文本文件,其 原始内容 都是 二进制的0和1 ,在 二进制 模式读写时,是以 字节 为单位。
在用 文本 模式读写文本文件时,是自动做了转换,将字节 转换 为字符
由于mp3、图片等二进制文件的内容,不利于人眼识别,在本节中,为了便于 查看内容,例子通常以 二进制 模式读取 文本 文件,而且更容易了解文本文件的本质。
打开文件
读写文件,要先通过内置open()函数打开文件
语法open('文件路径',mode='模式')
常用参数说明:
file: 必需,文件路径(相对或者绝对路径)。
mode: 可选,文件打开模式,可省略。详细介绍在下面
注意:
采用 二进制 模式读取文件时,不要 指定编码,否则报错:
ValueError: binary mode doesn't take an encoding argument
常用模式:
二进制文件(如图片,也可以读取文本文件等):
‘rb’:只读
文件指针放在文件的开头。
文件必须存在,否则抛异常
‘rb+’:读写
文件指针放在文件的开头
文件必须存在,否则抛异常
b是binary[ˈbaɪnəri] 的缩写
例子f=open('d:\\1.txt','rb')
文件指针
当对文件进行操作时,内部有 文件指针 定位当前内容的位置,当用 读取模式 打开文件时,文件指针指向文件的开始位置,读取长度是n的内容后,文件指针会移动到n+1的位置
所以 读完 整个文件后,如果不移动文件指针,将 无法再次读取文件内容
打开文件如下图:
当文件内容都是英文时,一个 字节 对应一个 英文字符
读取整个文件后如下图:
关闭文件
读写文件后应 及时关闭 。如果不关闭,那么 文件一直被占用,会出现问题,如:
不能改文件名
有时运行某软件时会提示XXX文件被占用,为了避免该情况,读写文件后应及时关闭
操作系统对 打开文件的次数有限制
当程序退出后,文件会释放
补充:
有的软件,在运行时, 会一直独占文件 ,这种时候,就不能关闭 。
如:word、ppt、excel等,在实现某软件服务器时,在运行期间要一直输出日志,所以一直独占日志文件
语法f.close()
例子
运行期间不关闭文件对象,无法对文件进行其他操作,如不能改名。
当程序退出后,会释放文件,可以做其他操作
见下面代码:
#coding=utf-8
import time
f=open('c:/users/mym/desktop/1.txt','rb')
time.sleep(10)#休眠10秒
在这10秒内,改变文件名称,弹出窗口如下:
10秒后程序退出,可以修改文件名
操作系统打开文件的次数有限制i=0
while True:
#文件对象会自动销毁
f=open('c:/users/mym/desktop/1.txt','rb')
no=f.fileno()#每打开一次文件,会加1
print(i,no)
i+=1
测试执行,发现f.fileno()返回的是固定几个值,是因为python自动回收了,修改如下:
i=0
l=[]
while True:
f=open('c:/users/mym/desktop/1.txt','rb')
l.append(f)#将文件对象添加到list中,就不会被自动销毁
no=f.fileno()#每打开一次文件,会加1
print(i,no)
print(i,f.fileno())
i+=1
测试执行,抛异常如下:
OSError: [Errno 24] Too many open files: 'c:/users/mym/desktop/1.txt'
打开文件次数过多
注意:
操作文件结束后要及时关闭文件
读取文件
读取是将存储在 硬盘 中的数据调入到 内存 中
方法1:
读取 全部内容 或者 指定的字符数 ,包括 换行符\n
语法:f.read([size])
参数
size:设置 读取的长度。文本文件模式以 字符 为单位,二进制文件模式以 byte 为单位,适用于读取 大文件
如果 未给定 或 负数 则 读取 所有,适用于读取 小文件 ,因为读取几个G的大文件,可能会将内存占满
返回值
返回读取的内容,bytes类型
例:1:
用 二进制 模式读取内容是 英文 的文本文件
使用windows自带的编辑器notepad,编辑内容如下:
Hello
Python
保存(默认保存是GBK编码),然后编写python程序,用二进制模式读取该文件,代码如下:
with open('c:/users/mym/desktop/0.txt','rb') as f:
data=f.read()
print(type(data))
print(data)
执行结果如下:
b'Hello\r\nPython'
注意:
用二进制模式读取文本文件,返回的数据类型是bytes(以字节为单位)
当文件内容全是ASCII码时,与文件内容相同,但注意前面的b,表示二进制,不是字符串。
注意\r\n,是windows的换行符,在用 文本文件 模式读取时,python内部转换为\n,用 二进制 模式读取,才能真正看到 原始内容
read()方法不带参数的用法,是读取全部内容,适用于读取小文件
例子2:
用 二进制 模式读取内容是 中文 的文本文件
使用windows自带的编辑器notepad,编辑内容如下:
床前明月光
保存(默认保存是GBK编码),然后编写python程序,用二进制模式读取该文件,代码如下:
with open('c:/users/mym/desktop/0.txt','rb') as f:
data=f.read()
print(data)
执行结果如下:
b'\xb4\xb2\xc7\xb0\xc3\xf7\xd4\xc2\xb9\xe2'
注意:
用二进制模式读取文本文件(GBK编码),1个汉字占2个字节,打印的结果是16进制,如下图:
例子3:
改造上面的程序,将读取的二进制数据 解码 为字符串:
with open('c:/users/mym/desktop/3.txt','rb') as f:
data=f.read()
#由于文本文件是以GBK编码方式保存的,所以用GBK编码解码成字符串,否则报错或乱码
content=data.decode('GBK')
print(content)
方法2(不报错,不推荐):
读取一行(即:遇到”\n”字符停止读取),包括 “\n” 字符。
适用于读取大文本文件,也适用读取二进制文件
语法:f.readline([size])
参数
size : 如果 未指定长度 或为 负数,读取一行。
如果是非负数,当size比一行的字符数小,那么就读取长度是size的内容;如果size比一行的字符数大,那么就读取一行
一般不指定
返回值
返回读取的内容,包括 “\n” 字符
方法3(不报错,不推荐):
读取所有行,并按照行放入到list中,包括 “\n” 字符
适用于读取文本文件,也适用读取二进制文件
语法f.readlines([size])
参数
size — 如果 未指定长度 或为 负数,读取所有行。
如果指定size,将返回接近size的行,也就是说可能只读到文件的一部分,且具体长度不确定。
一般不指定
返回值
返回列表,包含所有的行。
包括 “\n” 字符
注意
读取整个文件后,文件指针指向 文件末尾,再次读取将 没有内容
解决方法用f.seek(0),将文件指针移动到开头
移动文件指针
移动文件指针到指定位置,为负数时抛出异常
语法:f.seek(offset[, whence])
参数
offset — 移动的偏移量,单位:字节,不论文本还是二进制模式
whence — 可选,表示要从哪个位置开始偏移;
需要引入os模块,import os,值如下:os.SEEK_SET:从文件开头算起,默认值
os.SEEK_CUR:从当前位置算起。文本文件模式读取,不能设置此项
os.SEEK_END:从文件末尾算起。文本文件模式读取,只能设置到末尾,向前偏移报错
返回值
无
例子1with open('c:/users/mym/desktop/1.txt','rb') as f:
data=f.read()#读取文件后,文件指针指向末尾
print(data)
f.seek(0)#需要将文件指针指向开头,才能再次读取
data=f.read()
print(data)
例子2
使用windows自带文本编辑器notepad,新建文本文件,并通过notepad写入床前明月光,保存(默认保存采用GBK编码)。然后编写python程序,将文件指针移动1个字节,然后读取文件,代码如下:
with open('c:/users/mym/desktop/1.txt','r') as f:
c=f.seek(1)#移动一个字节
c=f.read()#读取文件
print(c)
执行报错,如下:
UnicodeDecodeError: 'gbk' codec can't decode byte 0xa1 in position 0: illegal multibyte sequence
报错原因:
notepad默认保存为GBK编码,一个汉字占用 2个字节 ,当 移动一个字节 ,开始读取时,无法正确将 字节 转为 汉字
UTF-8编码中汉字通常占3个字节,很生僻汉字占4-6个字节
注意:
由于上面原因,移动指针会造成错误,一般读取 文本文件 时不要移动文件指针
获取文件指针位置
语法:file.tell()
参数
无
返回值
返回文件指针的当前位置
例子:with open('c:/users/mym/desktop/1.txt','r') as f:
c=f.read()
print(c)
print(f.tell())