• 字符编码与文件处理


    字符编码

    前提摘要

    运行python程序的三个步骤:

    1. 先启动python解释器     2. 再将python文件当作普通的文本文件读入内存             3. 解释执行读入内存的代码,开始识别语法

    重点理论:
    1、 编码与解码:
    字符---编码-->unicode的二进制-------编码----->GBK的二进制
    GBK的二进制-----解码-->unicode的二进制----解码->字符

    2 、解决乱码问题的核心法则:
    字符用什么编码格式编码的,就应该用什么编码格式进行解码

    3、python解释器默认的字符编码         python2:ASCII         python3:UTF-8

    通过文件头可以修改python解释器默认使用的字符编码    在文件首行写:#coding:文件当初存的时候用的字符编码

    针对python2解释器中定义字符串应该:

    x=u""        对于python3解释即便是x=""不加u前缀也是存成unicode

    在python3中

    x=''                # '上'存成了uncidoe

    unicode--------encode----------->gbk
    res=x.encode('gbk')                #res是gbk格式的二进制,称之为bytes类型

    gbk(bytes类型)-------decode---------->unicode
    y=res.decode('gbk')                  #y就是unicode

    关于字符编码的操作:
    1. 编写python文件,首行应该加文件头:#coding:文件存时用的编码
    2. 用python2写程序,定义字符串应该加前缀u,如x=u'上'
    3. python3中的字符串都是unicode编码的,python3的字符串encode之后可以得到bytes类型

    unicode 分为 utf-32(占4个字节),utf-16(占两个字节),utf-8(占1-4个字节), so utf-16就是现在最常用的unicode版本, 不过在文件里存的还是utf-8,因为utf8省空间

    1. 以什么编码存的就要以什么编码取出
    内存固定使用unicode编码,我们可以控制的编码是往硬盘存放或者基于网络传输选择编码


    2 .数据是最先产生于内存中,是unicode格式,要想传输需要转成bytes格式
    #unicode----->encode(utf-8)------>bytes
    拿到bytes,就可以往文件内存放或者基于网络传输
    #bytes------>decode(gbk)------->unicode

    3.python3中字符串被识别成unicode
    python3中的字符串encode得到bytes

    4 .python2中的字符串就bytes  ,python2中在字符串前加u,就是unicode


    第一阶段:
    打开python解释器,notepad++,pychar 加载到内存
    第二阶段:
    写一个文件就是
    内存-endoce-bytes(二进制)
    显示文件就是:
    硬盘-decode-unicode(万国码)
    第三阶段:
    执行阶段,针对的是内部定义新的内存空间,例如变量
    数据是最先产生于内存中,是unicode格式,要想传输需要转成bytes格式
    unicode----->encode(utf-8)------>bytes
    拿到bytes,就可以往文件内存放或者基于网络传输
    bytes------>decode(gbk)------->unicode

    python解释器在加载 .py 文件中的代码时,会对内容进行编码(默认ascill)

    ASCII(American Standard Code for Information Interchange,美国标准信息交换代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言,其最多只能用 8 位来表示(一个字节),即:2**8 = 256-1,所以,ASCII码最多只能表示 255 个符号。

    关于中文

    为了处理汉字,程序员设计了用于简体中文的GB2312和用于繁体中文的big5。

    GB2312(1980年)一共收录了7445个字符,包括6763个汉字和682个其它符号。汉字区的内码范围高字节从B0-F7,低字节从A1-FE,占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE。

    GB2312 支持的汉字太少。1995年的汉字扩展规范GBK1.0收录了21886个符号,它分为汉字区和图形符号区。汉字区包括21003个字符。2000年的 GB18030是取代GBK1.0的正式国家标准。该标准收录了27484个汉字,同时还收录了藏文、蒙文、维吾尔文等主要的少数民族文字。现在的PC平台必须支持GB18030,对嵌入式产品暂不作要求。所以手机、MP3一般只支持GB2312。

    从ASCII、GB2312、GBK 到GB18030,这些编码方法是向下兼容的,即同一个字符在这些方案中总是有相同的编码,后面的标准支持更多的字符。在这些编码中,英文和中文可以统一地处理。区分中文编码的方法是高字节的最高位不为0。按照程序员的称呼,GB2312、GBK到GB18030都属于双字节字符集 (DBCS)。

    有的中文Windows的缺省内码还是GBK,可以通过GB18030升级包升级到GB18030。不过GB18030相对GBK增加的字符,普通人是很难用到的,通常我们还是用GBK指代中文Windows内码。

    显然ASCII码无法将世界上的各种文字和符号全部表示,所以,就需要新出一种可以代表所有字符和符号的编码,即:Unicode

    Unicode(统一码、万国码、单一码)是一种在计算机上使用的字符编码。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,规定虽有的字符和符号最少由 16 位来表示(2个字节),即:2 **16 = 65536,
    注:此处说的的是最少2个字节,可能更多

    UTF-8,是对Unicode编码的压缩和优化,他不再使用最少使用2个字节,而是将所有的字符和符号进行分类:ascii码中的内容用1个字节保存、欧洲的字符用2个字节保存,东亚的字符用3个字节保存...

    所以,python解释器在加载 .py 文件中的代码时,会对内容进行编码(默认ascill)

    文件操作

    1 什么是文件
    文件是操作系统提供给用户/应用程序的一种虚拟单位,该虚拟单位直接映射的是硬盘空间

    2 为何要处理文件
    用户/应用程序直接操作文件(读/写)就被操作系统转换成具体的硬盘操作,从而实现
    用户/应用程序将内存中的数据永久保存到硬盘中

    3 如何用文件

    文件处理的三个步骤:
    f=open(r'c.txt',mode='r',encoding='utf-8')              文件对象(应用程序的内存资源)======》操作系统打开的文件(操作系统的内存资源)
    print(f)
    data=f.read()
    f.close()                                                               向操作系统发送信号,让操作系统关闭打开的文件,从而回收操作系统的资源

    注:在同一个文件目录下的话,文件路径可以填相对路径(文件名),默认在当前文件夹查找;  文件路径前面的 r 是将文件路径中可能被转义的字符转换成原生字符串。


    操作文件内容的模式:

    控制操作文件内容格式的两种模式:t(默认的) b
    大前提: tb模式均不能单独使用,必须与纯净模式结合使用
    t文本模式:
    1. 读写文件都是以字符串为单位的
    2. 只能针对文本文件
    3. 必须指定encoding参数
    b二进制模式:
    1.读写文件都是以bytes/二进制为单位的
    2. 可以针对所有文件
    3. 一定不能指定encoding参数

    r模式:只读模式

    在文件不存在时则报错,如果文件存在文件指针跳到文件的开头

    with open(r'c.txt',mode='rt',encoding='utf-8') as f:
    print(f.read())
    print(f.readable())
    print(f.writable())
    f.write('hello') # 只能读
    
    data=f.read()
    print(data,type(data))
    
    with open(r'c.txt',mode='rb') as f:
    data=f.read()
    print(data,type(data))
    res=data.decode('utf-8')
    print(res)
    View Code

    上下文管理:
    with open(r'c.txt',mode='r',encoding='utf-8') as f,open(r'b.txt',mode='r',encoding='utf-8') as f1:
    pass

    循环读文件内容的方法:

    with open(r'c.txt',mode='rt',encoding='utf-8') as f:
    for line in f:
      print(line,end='')
    View Code

    w: 只写模式
    1 当文件不存时,新建一个空文档
    2 当文件存在时,清空文件内容,文件指针跑到文件的开头

    with open('c.txt',mode='wt',encoding='utf-8') as f:
    print(f.readable())
    print(f.writable())
    print(f.read())
    f.write('哈哈哈
    ')
    f.write('你愁啥
    ')
    f.write('瞅你咋地
    ')
    
    f.write('1111
    2222
    333
    4444
    ')
    
    info=['egon:123
    ','alex:456
    ','lxx:lxx123
    ']
    for line in info:
      f.write(line)
    f.writelines(info)
    
    with open('c.txt',mode='rb') as f:
    print(f.read())
    
    
    with open('c.txt',mode='wb') as f:
    f.write('哈哈哈
    '.encode('utf-8'))
    f.write('你愁啥
    '.encode('utf-8'))
    f.write('瞅你咋地
    '.encode('utf-8'))
    View Code

    a: 只追加写模式
    1 当文件不存时,新建一个空文档,文件指针跑到文件的末尾
    2 当文件存在时,文件指针跑到文件的末尾

    with open('c.txt',mode='at',encoding='utf-8') as f:
    print(f.readable())
    print(f.writable())
    f.read()
    
    f.write('虎老师:123
    ')
    
    
    在文件打开不关闭的情况下,连续的写入,下一次写入一定是基于上一次写入指针的位置而继续的
    with open('d.txt',mode='wt',encoding='utf-8') as f:
    f.write('虎老师1:123
    ')
    f.write('虎老师2:123
    ')
    f.write('虎老师3:123
    ')
    
    with open('d.txt',mode='wt',encoding='utf-8') as f:
    f.write('虎老师4:123
    ')
    
    with open('d.txt',mode='at',encoding='utf-8') as f:
    f.write('虎老师1:123
    ')
    f.write('虎老师2:123
    ')
    f.write('虎老师3:123
    ')
    with open('d.txt',mode='at',encoding='utf-8') as f:
    f.write('虎老师4:123
    ')
    View Code

    文本操作中的指针问题

    大前提:文件内指针的移动是Bytes为单位的,唯独t模式下的read读取内容个数是以字符为单位

    f.read() 无参数,读全部,有b按字节,无b按字符

    with open('a.txt',mode='rt',encoding='utf-8') as f:
         data=f.read(3)
         print(data)
    
    with open('a.txt',mode='rb') as f:
        data=f.read(3)
        print(data.decode('utf-8'))
    View Code
    f.seek(指针移动的字节数,模式控制): 控制文件指针的移动
     
    模式控制:
    0: 默认的模式,该模式代表指针移动的字节数是以文件开头为参照的
    1: 该模式代表指针移动的字节数是以当前所在的位置为参照的
    2: 该模式代表指针移动的字节数是以文件末尾的位置为参照的

    强调:其中0模式可以在t或者b模式使用,而1跟2模式只能在b模式下用
    f.tell()查看文件指针当前距离文件开头的位置
     

    0模式详解

    with open('a.txt',mode='rt',encoding='utf-8') as f:
      f.seek(4,0)
      print(f.tell())
      print(f.read())
    
    with open('a.txt',mode='rb') as f:
      f.seek(4,0)
      f.seek(2,0)
      print(f.tell())
      print(f.read().decode('utf-8'))
    
    
    with open('a.txt',mode='rt',encoding='utf-8') as f:
      f.seek(5,0)
      print(f.read())
    View Code

    1模式详解

    with open('a.txt',mode='rb') as f:
      f.seek(3,1)
      print(f.tell())
      f.seek(4,1)
      print(f.tell())
      print(f.read().decode('utf-8'))
    View Code

    2模式详解

    with open('a.txt',mode='rb') as f:
      f.seek(-9,2)
      data=f.read()
      print(data.decode('utf-8'))
    
    # tail -f access.log
    with open('access.log',mode='rb') as f:
      f.seek(0,2)
      while True:
      line=f.readline()
      if len(line) == 0:
        # 没有内容
        continue
      else:
        print(line.decode('utf-8'),end='')
    View Code

    文件修改

    须知一:
    硬盘空间无法修改,硬盘中的数据更新都是用新的内容覆盖旧的内容内存控制可以修改

    with open('a.txt','r+t',encoding='utf-8') as f:
      f.seek(4,0)
      print(f.tell())
      f.write('我擦嘞')
    View Code

    须知二:
    文件对应的是硬盘空间,硬盘不能修改应为文件本质也不能修改,我们看到文件的内容可以修改,是如何实现的呢?大的的思路:将硬盘中文件内容读入内存,然后在内存中修改完毕后再覆盖回硬盘具体的实现方式分为两种:

    1. 将文件内容发一次性全部读入内存,然后在内存中修改完毕后再覆盖写回原文件
    优点: 在文件修改过程中同一份数据只有一份
    缺点: 会过多地占用内存

    with open('db.txt',mode='rt',encoding='utf-8') as f:
      data=f.read()
    
    with open('db.txt',mode='wt',encoding='utf-8') as f:
      f.write(data.replace('kevin','SB'))
    View Code

    2. 以读的方式打开原文件,以写的方式打开一个临时文件,一行行读取原文件内容,修改完后写入临时文件...,删掉原文件,将临时文件重命名原文件名
    优点: 不会占用过多的内存
    缺点: 在文件修改过程中同一份数据存了两份

    import os
    
    with open('db.txt',mode='rt',encoding='utf-8') as read_f,
           open('.db.txt.swap',mode='wt',encoding='utf-8') as wrife_f:
      for line in read_f:
        wrife_f.write(line.replace('SB','kevin'))
    
    os.remove('db.txt')
    os.rename('.db.txt.swap','db.txt')
    View Code

    常用的文件操作大全(包括指针):

    windows里面的换行符实际是
    
    
    "+" 表示可以同时读写某个文件
    r+,可读写文件。【可读;可写;可追加】
    w+,写读
    a+,同a
    
    "U"表示在读取时,可以将 
     
     
    自动转换成 
     (与 r 或 r+ 模式同使用)
    rU
    r+U
    打开文件
    f = open('db','r',encoding="utf-8")    encoding="utf-8",就是python默认帮你二进制转换成字符串
    f = open('db','w')        先清空,后写入
    f = open('db','x')        文件存在报错,不存在创建写内容
    f = open('db','a')        追加
    f = open('db','rb')       不用python处理,我直接跟0101打交到
     
    data = f.read()
    print(data,type(data))   硬盘存的二进制,给我们显示的是字符串,那是不是有一个二 
                                        进制转换成字符串的过程
    f.close()
     
    f = open('db','ab')          字节追加
    f.write(bytes("hello",encoding='utf-8'))     将字符串转为字节,并且以utf-8写入
    f.close()
     
    r+指针变化
    f = open('db','r+',encoding="utf-8")    
    因为指针问题,默认读到了最后,如果你定义了读几个字符,那么指针会在第几个字 符那里,但是你要追加写的话就是从最后追加    
     
    read 将指针调到某个字符的位置,如果是rb打开就是字节的位置
    data = f.read(1)  一个字符
    print(f.tell())   位置就是3,按字节来的
    print(data)
      
    seek 就是按照字节的位置,并且是覆盖原来的字节位置,如果是中文的话,seek1就会给你劈开  �111111 乱码了
    f.seek(1)
    print(f.tell())   获取当前指针的位置
    f.write('1111')
    f.close()
     
    a+ 无论你怎么调指针的位置,都是最后结尾处加内容
    w+ 先清空,在写
    
    需要注意的是,如果该文件被打开或者使用'a''a+'追加,任何seek()操作将在下次写撤消
    
    在python中的某些时候,我们需要判断指针是否可以进行移动,而实现这样的需求需要采用seekable()方法。如果可以移动,返回True,如果不可以移动,返回False
    # seekable()方法,判断当前文件指针是否可以移动
    print(f.seekable())
     
    操作文件
    f = open('db','r+',encoding="utf-8")
    f.read()          无参数,读全部,有b按字节,无b按字符
    print(f.tell())   获取当前指针位置  字节
    f.seek()          调转到哪个位置  字节
    f.write()         写数据,有b就是写字节,无b就是字符
    f.close()         关闭文件
    f.flush()          强刷到硬盘,之前是存在缓冲区,等待close时候,才会刷到硬盘
    f.fileno()         文件描述符,用于后面的socker
    f.readable()    判断是否可读,跟模式有关
    f.seekable()     判断是否可以移动指针
    f.writable()     判断是否可写
    f.readline()     读取一行,这时候指针换行了
    f.readlines()    全部读取存为列表
    f.truncate()     截断数据,将指针后面的清空
    for line in f:     for 循环文件对象,一行一行
    print(line)
    View Code
  • 相关阅读:
    Spark实战练习03--Pair RDD
    Spark实战练习02--处理分隔符
    Spark实战练习01--XML数据处理
    做一个”合格“的程序员(二)——学习管理
    做一个“合格”的程序员(一)——基础能力
    图像处理算法之帧间差分法
    图像几何变换之透视变换
    图像几何变换之仿射变换
    内部排序之简单选择排序
    非极大值抑制算法
  • 原文地址:https://www.cnblogs.com/596014054-yangdongsheng/p/9673889.html
Copyright © 2020-2023  润新知