Python-学习笔记05(文件和编码)
文件编码解码
字符编码
Unicode 是 「字符集」 , UTF-8 是 「编码规则」
字符集:为每一个「字符」分配一个唯一的 ID(学名为码位 / 码点 / Code Point)
编码规则:将「码位」转换为字节序列的规则(编码/解码 可以理解为 加密/解密 的过程)
计算机内存里面使用的是 unicode,硬盘里面使用的是 utf-8。因为存储 utf-8 更加节约空间。
utf-8 是变长的也就意味着用户输入字符 “你好ab” 的时候,如果内存也用 utf-8 则需要经历一个计算的过程,然后才能存储,这个时候计算消耗的时间会非常的多(总时间 = 计算机时间 + 存储时间)但如果内存里面的编码采用 unicode 则不需要计算
我们现在使用的编辑器默认都是 utf-8
python 字符编码
python3 内部默认使用的是 unicode 码
# 编码与解码
s = 'hello world 你好'
# 编码:将人看的变成计算机能够看的懂的
res = s.encode('utf-8')
print(res) # b'hello world \xe4\xbd\xa0\xe5\xa5\xbd'
"""在python中的bytes类型你可以直接看成二进制格式"""
# 解码:将计算机看到懂的变成人能看的懂
print(res.decode('gbk'))
print(res.decode('utf-8'))
print(res.decode())
>>> b'hello world \xe4\xbd\xa0\xe5\xa5\xbd'
hello world 浣犲ソ
hello world 你好
hello world 你好
文件
计算机文件,是存储在某种长期储存设备上的一段数据流。其特点是所存信息可以长期、多次使用,不会因为断电而消失。
计算机文件可分为二种: 二进制文件和文本文件
- 图形文件及文字处理程序等计算机程序都属于二进制文件。
- 文本文件则是可以用文字处理程序阅读的简单文本文件。
文件读写步骤
- 打开文件
- 处理数据
- 关闭文件
open 函数
fileobj = open(filename, mode)
fileobj 是 open() 返回的文件对象,filename 是该文件的文件名。
mode 是指明文件类型和操作的字符串。
- mode 的第一个字母表明对其的操作。
- mode 的第二个字母是文件类型:
- t(可省略)代表文本类型文件;
- b 代表二进制类型文件。
文件打开模式
文件打开模式 | 含义 |
---|---|
“r” | 只读模式 (默认) |
“w” | 覆盖写模式 (不存在则新创建;存在则重写新内容) |
“a” | 追加模式 (不存在则新创建;存在则只追加内容) |
“x” | 创建写模式 (不存在则新创建;存在则出错) |
“+” | 与 r/w/a/x 一起使用,增加读写功能 |
“t” | 文本类型 |
“b” | 二进制类型 |
文件读写函数
名称 | 含义 |
---|---|
open() | 打开文件 |
read(size) | 从文件读取长度为size的字符串,如果未给定或为负则读取所有内容 |
readline() | 读取整行,返回字符串 |
readlines() | 读取所有行并 返回列表 |
write(s) | 把字符串 s 的内容写入文件 |
writelines(s) | 向文件写入一个元素为字符串的列表,如果需要换行则要自己加入每行的换行符。 |
seek(off, whence=0) | 设置文件当前位置 |
tell() | 返回文件读写的当前位置 |
close() | 关闭文件。关闭后文件不能再进行读写操作。 |
读取文本文件
文本文件内容(hello.txt):
Hello, I am emptinessboy! 你好,我是 emptinessboy!
文本方式打开:
textfile1 = open("hello.txt","rt",encoding="utf-8") # 打开文件(文本方式)
t = textfile1.readline() # 读取文件
print(t) # 处理数据(打印文件)
textfile1.close() # 关闭文件
>>> Hello, I am emptinessboy! 你好,我是 emptinessboy!
二进制方式打开:
textfile2 = open("hello.txt","rb") # 打开文件(二进制方式)
t = textfile2.readline() # 读取文件
print(t) # 处理数据(打印文件)
textfile2.close() # 关闭文件
>>> b'Hello, I am emptinessboy! \xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8c\xe6\x88\x91\xe6\x98\xaf emptinessboy!\r\n'
文件复制 demo
复制文件不需要考虑行结构,用 read 函数就可以了。这里将 hello.txt 复制为 hello_copy.txt
source1 = open("hello.txt","r",encoding="utf-8") # UTF-8模式读取原始文件并,赋给对象source1
source2 = open("hello_copy.txt","w",encoding="utf-8") # UTF-8模式读创建待写入文件并,赋给对象source2
s1 = source1.read() # 从文件1读取所有内容
source2.write(s1) # 写入内容
source2.close() # 关闭文件流
source1.close()
从复制后的文件可以看到,复制后的行结构没用改变
多行文件读写
多行文件读写
用 readlines() 读写多行文件,用嵌套列表存放多行内容
f=open("score.txt","r")
for line in f.readlines():
print(line) #处理行
f.close()
多行文本读取 demo
我们尝试读取下刚才的 hello_copy.txt
f1 = open("hello_copy.txt", "r", encoding="utf-8") # utf-8模式打开文件
f2 = f1.readlines() # 将多行变成列表(数组)
print(f2)
for l in f2:
print(l, end="")
f1.close()
>>> ['Hello, I am emptinessboy! 你好,我是 emptinessboy!\n', 'Hello, I am emptinessboy! 你好,我是 emptinessboy!\n', 'Hello, I am emptinessboy! 你好,我是 emptinessboy!']
Hello, I am emptinessboy! 你好,我是 emptinessboy!
Hello, I am emptinessboy! 你好,我是 emptinessboy!
Hello, I am emptinessboy! 你好,我是 emptinessboy!
实际应用:计算总评分:
这里先建一个如下格式的文本,用来存放测试信息:
这个案例中,我们使用嵌套列表来存放多行内容:我们计算每一个学生的总评
总评 = 笔试 * 50% + 平时 * 25% + 实验 * 25%
f = open("score", "r",encoding="utf-8")
head = f.readline() # 读表头行
newhead = head[:-1] + '\t总评成绩'
print(newhead)
for line in f.readlines(): # 这一步python会从我们刚才读取文件的位置继续往下读取,而不会从头开始
l = line.split() # 将读取的一行字符串继续按空格拆分为嵌套列表
# 例如第一行会变成 ['2050921018', '詹延峰', '计算数学', '65', '85', '76']
s = round(int(l[3]) * 0.5 + int(l[4]) * 0.25 + int(l[5]) * 0.25, 2) # 求总评分
print(' '.join(l) + ' ' + str(s)) # 加空格对齐
f.close()
运行效果:
文件操作拆解
f = open('a.txt','r',encoding='utf-8') # 默认就是r模式 read模式 只读模式
"""
在打开文本文件的时候如果你不指定编码,那么编码就依据当前操作系统的默认编码
windows GBK
linux utf8
Mac ASCII
"""
# f是一个文件对象 调用文件对象的一些方法就能够操作该文件
data = f.read()
f.close() # 向操作系统发起关闭文件的请求 回收资源
"""
打开一个文件包含两部分资源,应用程序的变量 f 和操作系统打开的文件。在操作完毕一个文件之后必须把与该文件的这两部分资源回收
变量 f 是python程序里面不需要你回收(python有自动的垃圾回收机制)
open 打开的资源存在与操作系统中(需要手工回收)
"""
with open 取代 open
with 用来创建临时运行环境
作用:with用于创建一个临时的运行环境,运行环境中的代码执行完后自动安全退出环境。
文件操作:使用 ope n进行文件操作使建议使用 with 创建运行环境,可以不用 close() 方法关闭文件,无论在文件使用中遇到什么问题都能安全的退出,即使发生错误,退出运行时环境时也能安全退出文件并给出报错信息。
关键字 with 用于上下文管理(推荐使用)
with open('a.txt','r',encoding='utf-8') as f:
data = f.read()
"""在执行完with代码块之后 with会自动帮你调用close方法"""
# with一次性打开多个文件
with open('a.txt','r',encoding='utf-8') as f1,\
open('b.txt','r') as f2:
pass
文件的操作模式
r 模式(read)
r 模式打开文件 文件必须存在否则直接报错。基本格式如下:
with open('a.txt','r',encoding='utf-8') as f:
pass
# 例如:
with open('a.txt','r',encoding='utf-8') as f:
data = f.read() # 读取文件内所有的内容
print(data)
基于 r 模式,实现用户认证功能,文件作为数据库:
username = input('>>>:').strip()
password = input('>>>:').strip()
with open('userinfo','r',encoding='utf-8') as f:
for line in f: # f文件对象可以被for循环 类似于一行行的读取文件内容
# 切割字符串
usr, pwd = line.strip('\n').split('|')
if username == usr and password == pwd:
print('登陆成功')
# 只要验证成功了 for循环就没有必要再执行了
break
else:
print('用户名或密码错误')
运行效果:
w 模式(write)
w 模式下文件不存在,也不会报错,反而会自动创建该文件。因此 w 模式一定要慎用,文件路径前面最好加一个 r 取消转义
- 先清空目标文件
- 才是写入内容
基本格式如下:
with open(r'b.txt','w',encoding='utf-8') as f:
pass
# 文件路径取消转义
with open(r'b.txt','w',encoding='utf-8') as f:
pass
简单写入案例:
with open('filew','w',encoding='utf-8') as f:
f.write('你追我...\n')
f.write('你追我...\n')
f.write('你追我...\n')
f.write('heiheihei 666\n')
# f.close 在 with 模式下可以不写
运行效果:
1.在文件不关闭的情况下 连续的写入,后写的内容一定跟在前写的内容后面
2.如果重新以w模式打开文件,则会先清空该文件
a 模式(append)
a 模式下文件不存在,也会自动创建该文件。文件存在的情况下 a 模式打开之后文件指针会直接移动到文件末尾。
with open('c.txt','a',encoding='utf-8') as f:
pass
with open('c.txt','a',encoding='utf-8') as f:
f.write('11111\n')
f.write('22222\n')
基于 a 模式实现用户的注册功能:
username = input('>>>:').strip()
password = input('>>>:').strip()
with open('userinfo.txt','a',encoding='utf-8') as f:
res = '%s|%s\n'%(username,password)
f.write(res)
运行效果:
+ 模式
Python 读写文件模式:在生产环境中我们只单纯的使用 r/w/a 读写分离,一般不用 +
- r 打开只读文件,该文件必须存在。
- r+ 打开可读写的文件,该文件必须存在。
- w 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
- w+ 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
- a 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。
- a+ 以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。
- 上述的形态字符串都可以再加一个 b 字符,如 rb、w+b 或 ab+ 等组合,加入 b 字符用来告诉函数库打开的文件为二进制文件,而非纯文字文件。不过在 POSIX 系统,Linux 都会忽略该字符。
规范
读写操作
最好先判断是否可读写:
print(f.readable()) # 判断当前是否可读
print(f.writable()) # 判断当前是否可写
读取文本文件的几种方法:
with open('a.txt','rt',encoding='utf-8') as f:
# 法一:
# 全部读取 当文件内容过大的时候 该方法可能会导致内存溢出
# 该方法执行完毕之后文件的指针会移动到文件末尾
data = f.read()
# 法二:
# 读取一行内容 指针会移动到第二行的首部
data = f.readline()
# 法三:
# 读取每一行内容 存放于列表中 当文件过大的情况下也不推荐使用
data = f.readlines()
# 法四(推荐):
# 我们在读取文件内容的时候 一般都是用for循环
for line in f:
print(line)
写入文本文件的推荐方法:
Python_write和writelines的区别
- write()需要传入一个字符串做为参数,否则会报错
- writelines()既可以传入字符串又可以传入一个字符序列,并将该字符序列写入文件
- 注意 :writelines必须传入的是字符序列,不能是数字序列。
- 错误写法如:list_1023 = [1,2,3,4,5]
with open('b.txt','wt',encoding='utf-8') as f:
f.write('111')
f.writelines(['aaa\n','bbb\n','ccc\n'])
# 立刻将内存数据刷到硬盘 类似于ctrl+s
f.flush()
修改文件
有两种方法可以实现文件修改:
- 将文件内容全部读取到内存 在内存中修改完毕之后覆盖原来的内容
- 重新创建一个新文件 然后将老文件内容一行行读取到内存修改之后写入新文件
之后将老文件删除 将新文件名修改为老文件名 完成替换
适用于小文件:
with open('a.txt','r',encoding='utf-8') as f:
data = f.read()
with open('a.txt','w',encoding='utf-8') as f:
f.write(data.replace('tony','jason')) #替换
上面的方法在文件修改过程中同一份数据只有一份。文件过大的时候比较吃资源。
适用于大文件:
import os
with open('a.txt','r',encoding='utf-8') as read_f,\
open('a.backend.txt','w',encoding='utf-8') as write_f:
for line in read_f:
write_f.write(line.replace('tony','jason')) #替换
os.remove('a.txt')
os.rename('a.backend.txt','b.txt')
这种方法不会占用太多的内存,不过在文件修改的时候同一份数据存了两份 比较消耗硬盘空间
主动控制文件内指针移动
大前提:文件内指针的移动都是 bytes 为单位,唯一列外的是 t 模式下的 read(n),n 是以字符串为单位。
# 字符模式
with open('a.txt','rt',encoding='utf-8') as f:
data = f.read(3) # 读取三个字符
print(data)
# 字节模式
with open('a.txt','rb') as f:
data = f.read(3) # 读取三个字节
print(data)
用 seek 控制指针
控制指针移动有三种模式,语法如下:
seek(指针移动的字节数,模式)
- 0 模式:以文件开头作为移动的参照
- 1 模式:以指针当前位置作为移动的参照
- 2 模式:以文件末尾作为移动的参照
其中 0 模式以在 t 和 b 下使用,而 1 和 2 模式只能在b模式下使用
测试文件如下:
# a.txt
哈哈哈1234567890
abcdefghijk
lmnopqrstuv
wxyz
吼
读取三个字符:
with open('a.txt','rt',encoding='utf-8') as f:
data = f.read(3) # 读取三个字符
print(data)
>>> 哈哈哈
读取三个字节:
with open('a.txt','rb') as f:
data = f.read(3) # 读取三个字节
print(data)
>>> b'\xe5\x93\x88'
光标向后移动三个字节:(t模式)
with open('a.txt','rt',encoding='utf-8') as f:
f.seek(3,0) # utf8用一个 bytes 表示英文 3个 bytes 表示中文
print(f.tell()) # 查看当前文件指针距离文件开头的位置 结果是3
print(f.read())
>>> 3
哈哈1234567890
abcdefghijk
lmnopqrstuv
wxyz
吼
光标向后移动六个字节:(b模式)
with open('a.txt','rb') as f:
f.seek(6,0)
print(f.read().decode('utf-8'))
>>> 哈1234567890
abcdefghijk
lmnopqrstuv
wxyz
吼

This blog is under a CC BY-NC-ND 4.0 Unported License
本文链接:https://coding.emptinessboy.com/2020/07/Python-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B005%EF%BC%88%E6%96%87%E4%BB%B6%E5%92%8C%E7%BC%96%E7%A0%81%EF%BC%89/