day09-字符编码补充以及文件处理

上节课复习

字符编码

英文字符----------------------->内存: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 EncodingProject 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'\xc9\xcf'
print(res.decode("gbk"))  # 上

2.文件处理

  • 控制文件读写操作的模式"

    • r:只读
    • w:只写
    • a:只追加
  • 控制文件读写内容的模式:

    • t:控制读写的内容都是字符串类型
      • 只适用于文本文件
      • 必须要只读encoding参数
    • b:控制读写的内存都是bytes类型
      • 一定不要指定encoding参数

    b使用的情况居多,因为文件存到硬盘都是存的二进制.

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\n")
f.write("你好啊2\n")  # 打开了文件不关闭的情况下,新写入的内容永远跟在老内容之后
f.write("你好啊3\n")
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)读取整行,包括 "\n" 字符。
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() 方法

功能:用于从文件读取整行,包括 "\n" 字符。如果指定了一个非负数的参数,则返回指定大小的字节数,包括 "\n" 字符。

语法: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() 方法

功能:用于向文件中写入一序列的字符串。

  • 这一序列字符串可以是由迭代对象产生的,如一个字符串列表。换行需要制定换行符 \n。

语法: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个亿\n')
    # 执行一遍就在末尾追加一行记录

# 监视着文件的动态,来一行打印一行
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:

在内存中进行修改,只用到一个文件

  1. 先将文件内容全部读入内存

  2. 在内存种完成修改

  3. 将修改后的内容覆盖回原文件

    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到另外一个文件,最后删除原文件,重命名新文件为原文件名称

  1. 以读的方式打开原文件,然后以写的方式打开一个临时文件

  2. 读原文件的一行内容到内存,然后在内存中修改完毕后在写入临时文件,循环往复直到全部改完

  3. 删除原文件,将临时文件重命名为原文件名

    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')
posted on 2020-12-25 21:38  Jkeykey  阅读(159)  评论(0)    收藏  举报