上节课复习
字符编码
英文字符----------------------->内存:ASCII格式的二进制------------------>硬盘:ASCII格式的二进制
中文字符,英文字符--------------->内存:gbk格式的二进制------------------>硬盘:gbk格式的二进制
日文字符,英文字符--------------->内存:ASCII格式的二进制--------------->硬盘:shift-jis格式的二进制
编码 编码
英文字符--------------->内存:ASCII格式的二进制------------------>硬盘:ASCII格式的二进制
英文字符--------------->内存:ASCII格式的二进制------------------>硬盘:ASCII格式的二进制
英文字符--------------->内存:ASCII格式的二进制------------------>硬盘:ASCII格式的二进制
如何保证不乱码:
存乱了:
1.统一用utf-8编码存入硬盘
读乱了:
2.将读的编码改成与存的编码一致
今日内容
1.字符编码
前言:
运行python程序的三个步骤:python a.py
1. 先启动python
2. 解释器会将文本文件a.py内容由硬盘读入内存
3. 解释器会解释执行刚刚读入内存的内容,识别python语法
在python程序执行的前俩步涉及到字符编码时
Python2中默认的编码格式是 ASCII 格式,在没修改编码格式时无法正确打印汉字,所以在读取中文时会报错。
解决方法为只要在文件开头加入 # -*- coding: UTF-8 -*- 或者 # coding=utf-8 就行了
注意:****# coding=utf-8 的 = 号两边不要空格。
Python3.X 源码文件默认使用utf-8编码,所以可以正常解析字符,无需指定 UTF-8 编码。
注意:如果你使用编辑器,同时需要设置 py 文件存储的格式为 UTF-8,否则会出现类似以下错误信息:
SyntaxError: (unicode error) ‘utf-8’ codec can’t decode byte 0xc4 in position 0:
invalid continuation byte
Pycharm 设置默认字符编码步骤:
- 进入 file > Settings,在输入框搜索 encoding。
- 找到 Editor > File encodings,将 IDE Encoding 和 Project Encoding 设置为utf-8。
print()功能对字符串类型的特殊照顾之申请内存空间
print()会对字符串类型的二进制做特殊的处理"
在python3中将字符对应的Unicode二进制存到内存空间中,取的时候,会将这个unicode二进制数解码成字符,所以在python3中看不到unicode的二进制数,会直接返回人类的字符
而在python2中,它又会将unicode二进制转成指定的其他编码的格式的二进制放到内存空间中,它在反解的时候会根据不同的调用者(cmd,pycharm)去将Unicode二进制
转成字符,因为调用者的解码的那个字符编码表是设置死的,这时候,它会存在俩个字符编码表不一致的情况,就会发生乱码
解决方案: 在python2 中定义一个变量 字符前面加个 u 表示将它存到内存空间强制存为Unicode的二进制,又可以
通过Unicode的二进制和字符的对应关系解码直接变为字符打印出来
但是将字符类型的存到一个列表中,你又会发现,他取出来的还是unicode的二进制,并不会输出字符.
总结:
python3在第三步时会将unicode二进制存到内存空间,然后直接反解码成字符
python2会将Unicode二进制转换成对应的编码的二进制,解码
强调:在python3里,只会将Unicode格式的数字转成字符
编码和解码的过程
编码 编码
字符-------------------->unicode------------->其他编码
解码 解码
字符<--------------------unicode<-------------其他编码
x = "上" # 内存中存的是'上'这个字符的unicode的二进制数
print(x) # 上 本解释器为python3 可以直接将字符类型
print([x,]) # ===> ['上'] # 不管存到了其他数据类型中还是字符类型,都会将字符串打印到终端
res = x.encode("gbk") # 将unicode二进制x通过gbk编码成gbk二进制
print(type(res)) # <class 'bytes'> # 类型是bytes
# 强调:在python3里,只会将unicode格式的数字转成字符,其余编码格式的数字均不会转换
print(res) # b'xc9xcf'
print(res.decode("gbk")) # 上
2.文件处理
-
控制文件读写操作的模式"
- r:只读
- w:只写
- a:只追加
-
控制文件读写内容的模式:
- t:控制读写的内容都是字符串类型
- 只适用于文本文件
- 必须要只读encoding参数
- b:控制读写的内存都是bytes类型
- 一定不要指定encoding参数
b使用的情况居多,因为文件存到硬盘都是存的二进制.
- t:控制读写的内容都是字符串类型
3.文件读写方法
r:只读
r:如果文件不存在则报错,文件存在则将文件指针跳转到整个文件的开头
完整语法:f = open('file_path', mode='rt', encoding='')
- file_path为读的文件的路径
- mode=''为指定的模式
- encoding=''为指定按照上面字符编码表解码到内存
案例:打印出a.txt中的所有内容
f = open('a.txt', mode='rt', encoding='utf-8')
print(f.read())
f.close()
w:只写
w:如果文件不存在则创建空文档,如果文件存在则清空,文件指针跳转到文件开头
完整语法::f = open('file_path', mode='wt', encoding='')
- file_path为写的文件的路径
- mode=''为指定的模式
- encoding=''为指定按照上面字符编码表编码到硬盘
案例:往c.txt文件中写入一些内容
f = open('c.txt', mode='wt', encoding='utf-8')
f.write('你好啊1')
f.write('你好啊2') # 打开了文件不关闭的情况下,新写入的内容永远跟在老内容后面
f.write('你好啊3')
f.close()
a:追加模式
a: 如果文件不存则创建空文档,如果文件存在则清空,文件指针跳到文件末尾
完整语法::f = open('file_path', mode='at', encoding='')
- file_path为写的文件的路径
- mode=''为指定的模式
- encoding=''为指定按照上面字符编码表编码到硬盘
案例:往c.txt文件中追加内容
f = open(r'c.txt',mode='at',encoding='utf-8')
f.write("你好啊1
")
f.write("你好啊2
") # 打开了文件不关闭的情况下,新写入的内容永远跟在老内容之后
f.write("你好啊3
")
f.close()
读写模式
r+t 在保持读的基本情况下还可以写
w+t 在保持写的基本情况下还可以读
a+t 在保持追加写的基本情况下还可以读
例如:读写c.txt中的内容
f = open(r'c.txt',mode='r+t',encoding='utf-8')
print(f.readable())
print(f.writable())
print(f.read())
f.write("h")
f.close()
b模式
必须配合r,w,a 使用
作用:不仅可以读写普通的文本文件还可以读写操作二进制的文件,原理是都是以二进制的类型进行操作
b模式配合读写操作文件案例:
将c.txt文件的bytes类型的二进制读取出来
with open('c.txt',mode='rb') as f:
res = f.read()
# print(type(res))
# print(res) # 结果是bytes类型的二进制
print(res.decode('utf-8')) # 可以解码成原本的字符
将1.mp4这个视频文件的内容读取出来
with open('1.mp4',mode='rb') as f:
print(f.read())
for line in f:
print(line)
copy一份1.mp4的视频文件
with open('1.mp4',mode='rb') as src_f,open(r'D:111111.mp4',mode='wb') as dst_f:
for line in src_f:
dst_f.write(line)
怎么将字符以bytes类型的二进制写入到文件中
with open('d.txt',mode='wb') as f:
msg = "你好"
f.write(msg.encode('utf-8'))
file 对象使用 open 函数来创建,下表列出了 file 对象常用的函数:
序号 | 方法及描述 |
---|---|
1 | file.close()关闭文件。关闭后文件不能再进行读写操作。 |
2 | file.flush()刷新文件内部缓冲,直接把内部缓冲区的数据立刻写入文件, 而不是被动的等待输出缓冲区写入。 |
3 | file.fileno()返回一个整型的文件描述符(file descriptor FD 整型), 可以用在如os模块的read方法等一些底层操作上。 |
4 | file.isatty()如果文件连接到一个终端设备返回 True,否则返回 False。 |
5 | file.next()返回文件下一行。 |
6 | file.read(size)从文件读取指定的字节数,如果未给定或为负则读取所有。 |
7 | file.readline(size)读取整行,包括 " " 字符。 |
8 | file.readlines(sizeint)读取所有行并返回列表,若给定sizeint>0,则是设置一次读多少字节,这是为了减轻读取压力。 |
9 | file.seek(offset, whence)设置文件当前位置 |
10 | file.tell()返回文件当前位置。 |
11 | file.truncate(size)截取文件,截取的字节通过size指定,默认为当前文件位置。 |
12 | file.write(str)将字符串写入文件,返回的是写入的字符长度。 |
13 | file.writelines(sequence)向文件写入一个序列字符串列表,如果需要换行则要自己加入每行的换行符。 |
比较常用的方法
read()方法
功能:用于从文件读取指定的字节数,如果未给定或为负则读取所有。
语法: fileObject.read([size])
size
-- 从文件中读取的字节数,默认为 -1,表示读取整个文件。
返回值:返回从字符串中读取的字节。
readline() 方法
功能:用于从文件读取整行,包括 " " 字符。如果指定了一个非负数的参数,则返回指定大小的字节数,包括 " " 字符。
语法:fileObject.readline(size)
size
-- 从文件中读取的字节数
readlines()方法
功能:用于读取所有行(直到结束符 EOF)并返回列表,该列表可以由 Python 的 for... in ... 结构进行处理。
如果碰到结束符 EOF 则返回空字符串。
语法:fileObject.readlines( )
返回值: 返回列表,包含所有的行。
write() 方法
功能:用于向文件中写入指定字符串。
注意:
在文件关闭前或缓冲区刷新前,字符串内容存储在缓冲区中,这时你在文件中是看不到写入的内容的。
如果文件打开模式带 b,那写入文件内容时,str (参数)要用 encode 方法转为 bytes 形式,否则报错:TypeError: a bytes-like object is required, not 'str'。
语法:fileObject.write( [ str ])
str
为当wt就是字符串/当是wb模式则是字节
返回值: 返回的是写入的字符长度。
writelines() 方法
功能:用于向文件中写入一序列的字符串。
- 这一序列字符串可以是由迭代对象产生的,如一个字符串列表。换行需要制定换行符 。
语法:fileObject.writelines( [ str ])
str
为当wt就是字符串列表/当是wb模式则是字节
没有返回值
seek() 方法
功能:用于移动文件读取指针到指定位置。
语法:fileObject.seek(offset[, whence])
offset
-- 开始的偏移量,也就是代表需要移动偏移的字节数whence
可选,默认值为 0。给offset参数一个定义,表示要从哪个位置开始偏移;0代表从文件开头开始算起,1代表从当前位置开始算起,2代表从文件末尾算起。- 注意:只有0模式可以在t下使用,1和2只能在b模式下使用
返回值: 如果操作成功,则返回新的文件位置,如果操作失败,则返回 -1。
实例1:
with open('a.txt',mode='rt',encoding='utf-8') as f:
f.seek(3,0)
f.seek(5,0)
print(f.tell()) # 5
with open('a.txt',mode='rb') as f:
f.seek(3,1)
f.seek(5,1)
print(f.tell()) # 8
res=f.read()
print(res.decode('utf-8'))
with open('a.txt',mode='rb') as f:
f.seek(-3,2)
print(f.tell())
f.seek(0,2)
练习:动态监测文件最后一行加入的内容
import time
with open('access.log',mode='at',encoding='utf-8') as f7:
f7.write(f'{time.strftime("%Y-%m-%d %H:%M:%S")},jkey给liu转了1个亿
')
# 执行一遍就在末尾追加一行记录
# 监视着文件的动态,来一行打印一行
with open('access.log', mode='rb') as f8:
f.seek(0, 2) # 将指针一直放在末尾
while True:
line4 = f8.readline()
if len(line4) == 0:
time.sleep(0.1)
else:
print(line4.decode('utf-8'), end='')
pass
4.文件修改的俩种方式
修改文件的方式1:
在内存中进行修改,只用到一个文件
-
先将文件内容全部读入内存
-
在内存种完成修改
-
将修改后的内容覆盖回原文件
ps : 耗内存不消耗硬盘
with open('access.log') as f9:
data = f9.read()
with open('access.log',mode='wt', encoding='utf-8') as f10:
f10.write(data.replace('egon','EGON'))
修改文件的方式2:
一行一行的copy到另外一个文件,最后删除原文件,重命名新文件为原文件名称
-
以读的方式打开原文件,然后以写的方式打开一个临时文件
-
读原文件的一行内容到内存,然后在内存中修改完毕后在写入临时文件,循环往复直到全部改完
-
删除原文件,将临时文件重命名为原文件名
ps : 耗硬盘不消耗内存
import os
with open('name.txt', 'rt', encoding='utf-8') as f1,
open('name1.txt', 'wt', encoding='utf-8') as f2:
for i in f1:
i = i.replace('alex', 'sb')
f2.write(i)
os.remove('name.txt')
os.rename('name1.txt', 'name.txt')