字符编码、文件处理、指针移动

目录:

  字符编码

  文件处理

  指针移动

字符编码:

储备知识点:
    1. 计算机系统分为三层:
        应用程序
        操作系统
        计算机硬件

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

代码是在编辑器写的,不存在任何语法。

边写边存到内存(Unicode编码),然后再通过解码显示到显示屏。从内存刷到硬盘时候,是从Unicode转换成你要保存的格式(GBK)。

从硬盘读取出来的时候,先通过保存的格式(GBK)解码成Unicode到内存中,再用Unicode解码成原先写的字符。

 


字符编码

1. 什么是字符编码
字符编码表: 人类的字符<------------>数字
        1Bytes=8bit
        1B=8b 1字节等于8个二进制位
常用的编码表:
        ASCII码:只能识别英文字符,1英文字符=8bit=1Bytes
                用8个二进制bit(比特位)位表示一个英文字符

        GBK:能识别汉字与英文,1汉字=16bit=2Bytes,1英文字符=8bit=1Bytes

        unicode:能够识别万国字符,1字符=2Bytes=16bit
            两大特点:
                1. 能够兼容万国字符
                2. 与各个国家的字符编码都有映射关系
        utf-8:是unicode的转换格式,在往硬盘存储时从unicode精简为utf-8,即从16bit转换为8bit,节省存储空间来提高运行速度。
          1个英文字符=1Bytes  1汉字=3Bytes

字符串类型演变:
        
            python2有两种"字符串"相关类型:
                种类一
                #coding:gbk
                x='' # '上'存成了GBK编码后的二进制

                种类二:
                x=u'' # '上'存成了unicode编码后的二进制


            python3有两种"字符串"相关类型
                x='' # '上'存成了unicode编码后的二进制

                res=x.encode('gbk') #gbk格式的二进制
        重点理论:
1 编码与解码:
                字符(输入)---编码-->unicode的二进制(存内存)-------编码----->GBK的二进制(存硬盘)
                GBK的二进制(硬盘)-----解码-->unicode的二进制(内存)----解码->字符(显示器)
            2 解决乱码问题的核心法则:
字符用什么编码格式编码的,就应该用什么编码格式进行解码

3 python解释器默认的字符编码
python2:ASCII(程序加载到内存中的时候都是unicode,开始识别语法时候会定义字符串变量,就会继续在内存中开辟空间,会使用ASCII编码)
python3:Utf-8(Python3中,定义字符串变量时候,默认使用Unicode编码,和内存默认编码相同)

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

针对python2解释器中定义字符串应该:
x=u"上"
对于python3解释即便是x="上"不加u前缀也是存成unicode
-------------------------------------------------------------------------------------------------
在python3中:
x='上'   #上存成了unicode
unicode--------encode(编码)----------->gbk(存储到硬盘时候转换成gbk)
   res=x.encode('gbk') #res是gbk格式的二进制,称之为bytes类型
gbk(bytes类型)-------decode(解码)---------->unicode
y=res.decode('gbk') #y就是unicode
-------------------------------------------------------------------------------------------------
关于字符编码的操作(结论
1. 编写python文件,首行应该加文件头:#coding:文件存时用的编码(不用担心Python程序运行的前两个阶段,不会出现乱码)
2. 用python2写程序,定义字符串应该加前缀u,如x=u''
3. python3中的字符串都是unicode编码的,python3的字符串encode之后可以得到bytes类型

  2. 为何字符要编码
    人类与计算机打交道用的都是人类的字符,而计算机无法识别人类的字符,只能识别
    二进制,所以必须将人类的字符编码成计算机能识别的二进制数字.   3. 如何用字符编码

文件处理:

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

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

3 如何用文件

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

上下文管理:(使用这种打开方式不用自己去关闭文件,在程序结束时会自动关闭文件
with open(r'c.txt',mode='r',encoding='utf-8') as f,open(r'b.txt',mode='r',encoding='utf-8') as f1:
    读写文件的操作
    pass
大前提: tb模式均不能单独使用,必须与纯净模式结合使用

操作文件内容的模式:t(默认),b
  t(默认的):操作文件内容都是以字符串为单位,会自动帮我们解码,必须指定encoding参数(解码时候没人告诉计算机用什么解码,而window系统默认是GBK编码,所以要指定)
  b: 操作文件内容都是以Bytes(二进制)为单位,硬盘中存的时什么就取出什么,一定不能指定encoding参数
t文本模式:
  1. 读写文件都是以字符串为单位的
  2. 只能针对文本文件
  3. 必须指定encoding参数
b二进制模式:
  1.读写文件都是以bytes/二进制为单位的
  2. 可以针对所有文件
  3. 一定不能指定encoding参数
  总结:t模式只能用于文本文件,而b模式可以用于任意文件(如图片,视频,文本)

文件打开的三种纯净模式:r(默认的) w a

一、r模式:只读模式,在文件不存在时则报错,如果文件存在文件指针跳到文件的开头
with open(r'c.txt',mode='rt',encoding='utf-8') as f:(红色r代表原生字符,没有转义,可以避免\n被当成换行符号print(f.read())
    print(f.readable())
    print(f.writable())
    f.write('hello') # 报错,只能读

    data=f.read()
    print(data,type(data))#str

 

with open(r'c.txt',mode='rb') as f:
    data=f.read()             #b模式
    print(data,type(data))       #b'jinrui:123\r\nxuechengeng:12345\r\negon:1234\r\nalex:alex123' <class 'bytes'>
    res=data.decode('utf-8')
    print(res)

with open(r'c.txt',mode='rt',encoding='utf-8') as f:
    line=f.readline()
    print(line,end='')
    line1=f.readline()      #一行一行的读,读完文件没有关闭的话,指针会跳到下一行的开头;如果文件关闭的话指针重新回到起点。
    print(line1,end='')
    line2 = f.readline()
    print(line2,end='')

    lines=f.readlines()     #一次读多行
    print(lines)

 循环读文件内容的方法:

with open(r'c.txt',mode='rt',encoding='utf-8') as f:  #f是文件对象
    for line in f:
        print(line,end='*')
    #  egon:123
      *alex:456
      *lxx:789*        #正常的\n有换行,print也有换行,但是end('=')覆盖了\n,

 二、w模式:只写模式 在文件不存在时会创建空文档,文件存在会清空文件,文件指针跑到文件开头

 

with open('b.txt',mode='wt',encoding='utf-8') as f:
    print(f.writable())
    print(f.readable())
    f.write('你好\n')
    f.write('我好\n') # 强调:在文件不关闭的情况下,后写的内容一定跟着前写内容的后面
    f.write('大家好\n')
    f.write('111\n222\n333\n')

    lines=['1111','22222','33333']
    for line in lines:
        f.write(line)  #11112222233333。没有\n不会换行;
    f.writelines(lines)  #不是写很多行的意思,而是上面for循环的简写模式,没有\n不会换行
三、a模式:只追加写模式 在文件不存在时会创建空文档,文件存在会将文件指针直接移动到文件末尾,追加内容

# r+ w+ a+,读写模式
with open('a.txt',mode='r+t',encoding='utf-8') as f:
    print(f.readable())
    print(f.writable())
    print(f.readline())
    f.write('你好啊')

 

with open('d.txt','wb') as f:
    f.write('你好'.encode('gbk'))  #在d.txt文件中写入‘你好’,用gbk编码,所以要查看必须用gbk模式查看

实现功能代码:
注册:

1 name = input('用户名:')
2 pwd = input('密码:')
3 with open('db.txt',mode='at',encoding='utf-8') as f:
4     info = '%s:%s\n'%(name,pwd)
5     f.write(info)
6     print('注册成功')
View Code
登录:
 1 # coding:utf-8
 2 name = input('请输入用户名:>').strip()
 3 pwd = input('请输入密码:>').strip()
 4 with open(r'c.txt', mode='rt', encoding='utf-8') as f:
 5     for line in f:
 6         n, p = line.strip('\n').split(':')
 7         if name == n and pwd == p:
 8             print('登录成功')
 9             break
10     else:
11         print('账号或密码错误')
View Code
拷贝文件:
1 src_file=input('源文件路径:')
2 drc_file=input('目标路径:')
3 with open(r'%s'%src_file,mode='rb') as f,open(r'%s'%drc_file,mode='wb') as f1:
4     for line in f:
5         f1.write(line)
View Code

 指针移动:

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

文本读取模式:

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'))
f.seek(指针移动的字节数,模式控制): 控制文件指针的移动,都是以字节为单位
模式控制:
  0: 默认的模式,该模式代表指针移动的字节数是以文件开头为参照的
  1: 该模式代表指针移动的字节数是以当前所在的位置为参照的
  2: 该模式代表指针移动的字节数是以文件末尾的位置为参照的
强调:其中0模式可以在t或者b模式使用,而1跟2模式只能在b模式下用
  f.tell()查看文件指针当前距离文件开头的位置

  # 0模式详解:文件开头

a.txt文件第一行内容:你a我擦嘞111
with open('a.txt',mode='rt',encoding='utf-8') as f:
    f.seek(4,0)      #从文件开头,读取四个字节
    print(f.tell())
    print(f.read())    #从4开始往后读完

with open('a.txt',mode='rb') as f:
f.seek(4,0)
# f.seek(2,0)    #报错,因为没有完整截到一个字符你,在decode时会报错
print(f.tell())
print(f.read().decode('utf-8'))

with open('a.txt',mode='rt',encoding='utf-8') as f:
f.seek(5,0)     #5将我拆分了
print(f.read())  #报错,t模式下的read是以字符为单位
 # 1模式详解:当前位置
with open('a.txt',mode='rb') as f:
    f.seek(3,1)
    print(f.tell())  #3
    f.seek(4,1)     
    print(f.tell())  #7,正好是我字结束
    print(f.read().decode('utf-8'))  #可以正常打印
# 2模式详解:
with open('a.txt',mode='rb') as f:
    f.seek(-9,2)      #-9是向前移动九位
    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='')
文件的修改:
须知一:
  硬盘空间无法修改,硬盘中的数据更新都是用新的内容覆盖旧的内容
  内存内容可以修改
硬盘上直接覆盖:
with open('a.txt','r+t',encoding='utf-8') as f:   f.seek(4,0)   print(f.tell())   f.write('我擦嘞') #是直接将原位上的数据覆盖了,不存在插入
须知二:
  文件对应的是硬盘空间,硬盘不能修改因为文件本质也不能修改

我们看到文件的内容可以修改,是如何实现的呢?
  大的的思路:将硬盘中文件内容读入内存,然后在内存中修改完毕后再覆盖回硬盘

修改文件的两种方式:
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'))
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')

 

 
posted @ 2018-09-19 20:04  ChuckXue  阅读(329)  评论(0编辑  收藏  举报