Python字符编码及文件相关

一、字符编码相关

  1.介绍:

    常见编码有ascii编码(美国),GBK编码(中国),shift_JIS编码(日本),unicode(统一编码)等。

    python 2.x默认的字符编码是ASCII,默认的文件编码也是ASCII。

    python 3.x默认的字符编码是unicode,默认的文件编码是utf-8。

    Python支持中文的编码:utf-8、gbk和gb2312。uft-8为国际通用,常用有数据库、编写代码。gbk如windows的cmd使用。

 

  2.中文乱码问题:

    无论以什么编码在内存里显示字符,存到硬盘上都是二进制,所以编码不对,程序就会出错。存到硬盘上时是以何种编码存的,再从硬盘上读出来时,就必须以何种编码读,要不然就会出现乱码问题。                由于所有的系统、编程语言都默认支持unicode。所以只需要把unicode作为编码解码的中间媒介。    

    转码的过程:

      源有编码 -> unicode编码 -> 目的编码

      decode("UTF-8") 解码 --> unicode  --> encode("gbk") 编码

 

  3.Python2.x与Python3.x区别

    在python2.x中有两种字符串类型str和unicode

    例如:当python解释器执行到产生字符串的代码时(例如s='学习'),会申请新的内存地址,然后将'学习'编码成文件开头指定的编码格式要想看s在内存中的真实格式,可以将其放入列表中再打印,而                             不要直接打印,因为直接print()会自动转换编码

>>>s = ”学习“
>>>print s
学习
>>>s    # 字节类型
'\xd1\xa7\xcf\xb0'   

unicode类型:

    当python解释器执行到产生字符串的代码时(例如s=u'林'),会申请新的内存地址,然后将'林'以unicode的格式存放到新的内存空间中,所以s只能encode,不能decode转换在字符前加u‘,Windows默                 认的编码是“gbk”格式,而pycharm默认的是--**--Unicode--**--utf-8格式,编码如果不统一,解码时就会显示乱码,或者会报错,保证不乱码的前提是编码要统一,不 然就进行强制转换

#coding:gbk
x=u'' #等同于 x='上'.decode('gbk')
y=u'' #等同于 y='下'.decode('gbk')
print([x,y]) #[u'\u4e0a', u'\u4e0b']
print(type(x),type(y)) #(<type 'unicode'>, <type 'unicode'>)

 

      Python3中str都是Unicode编码的,所以Python3中的str类型的数据可以编码成其他字符编码的格式,编码的结果为bytes类型。

# coding:gbk
x = ''  # 当程序执行时,无需加u,'上'也会被以Unicode形式保存新的内存空间中,

print(f"type(x): {type(x)}")  # <class 'str'>

# x可以直接encode成任意编码格式
print(f"x.encode('gbk'): {x.encode('gbk')}")  # b'\xc9\xcf'
print(f"type(x.encode('gbk')): {type(x.encode('gbk'))}")  # <class 'bytes'>

 

二、文件操作

  基本操作

  1、打开文件

    得到文件句柄,可以复制给一个变量

# windows路径分隔符问题
# open('C:\a.txt\nb\c\d.txt')
# 解决方案一:推荐
# open(r'C:\a.txt\nb\c\d.txt')
# 解决方案二:
# open('C:/a.txt/nb/c/d.txt')
 
 
f=open(r'aaa/a.txt',mode='rt') # f的值是一种变量,占用的是应用程序的内存空间,此时打开文件
# print(f)
# x=int(10)

  2、操作文件

    文件的操作:读、写、修改、添加(f.read、f.close、f.open)要定义打开的模式不然默认为 mode='r'  )# r取消转义。读/写文件,应用程序对文件的读写请求都是在向操作系统发送系统调用,然后         由操作系统控制硬盘把输入读入内存、或者写入硬盘

res=f.read()
print(type(res))
# print(res)

#关闭文件
f.close() # 回收操作系统资源

  3、with上下文管理

# 文件对象又称为文件句柄

# with open('a.txt',mode='rt') as f1: #等同于f1=open('a.txt',mode='rt')
#     res=f1.read()
#     print(res)
 
 
with open('a.txt',mode='rt') as f1,\
        open('b.txt',mode='rt') as f2:
    res1=f1.read()
    res2=f2.read()
    print(res1)
    print(res2)
 
    # f1.close()
    # f2.close()

  4、指定字符编码

'''
强调:t和b不能单独使用,必须跟r/w/a连用,r代表read,w代表write,a代表追加写模式,不会创造新的文件,也不会清除源文件内容
 
t文本(默认的模式)
1、读写都以str(unicode)为单位的
2、文本文件
3、必须指定encoding='utf-8'
 
'''
# 没有指定encoding参数操作系统会使用自己默认的编码
# linux系统默认utf-8
# windows系统默认gbk
with open('c.txt',mode='rt',encoding='utf-8') as f:
    res=f.read() # t模式会将f.read()读出的结果解码成unicode
    print(res,type(res))
 
 
 
# 内存:utf-8格式的二进制-----解码-----》unicode
# 硬盘(c.txt内容:utf-8格式的二进制)

  5、文件操作模式

#1. 打开文件的模式有(默认为文本模式):
r ,只读模式【默认模式,文件必须存在,不存在则抛出异常】
w,只写模式【不可读;不存在则创建;存在则清空内容】
a, 之追加写模式【不可读;不存在则创建;存在则只追加内容】

#2.对于文本文件,我们用t模式,读写都以str(unicode)为单位的.一定要指定encoding='utf-8'
rt
wt
at
#3. 对于非文本文件,我们只能使用b模式,"b"表示以字节的方式操作(而所有文件也都是以字节的形式存储的,使用这种模式无需考虑文本文件的字符编码、图片文件的jgp格式、视频文件的avi格式)
rb
wb
ab
注:以b方式打开时,读取到的内容是字节类型,写入时也需要提供字节类型,不能指定编码

#4. 了解部分
"+" 表示可以同时读写某个文件
r+, 读写【可读,可写】
w+,写读【可读,可写】
a+, 写读【可读,可写】


x, 只写模式【不可读;不存在则创建,存在则报错】
x+ ,写读【可读,可写】
xb

    案例:

# 以t模式为基础进行内存操作
 
# 1、r(默认的操作模式):只读模式,当文件不存在时报错,当文件存在时文件指针跳到开始位置
inp_username=input('your name>>: ').strip()
inp_password=input('your password>>: ').strip()

with open('user.txt',mode='rt',encoding='utf-8') as f:
    for line in f:
        print(line,end='')          # aaa:123\n
        username,password=line.strip().split(':')
        if inp_username == username and inp_password == password:
            print('login successfull')
            break
        else:
            print('账号或密码错误')
 
 
# 2、w:只写模式,当文件不存在时会创建空文件,当文件存在会清空文件,指针位于开始位置#with open('d.txt',mode='wt',encoding='utf-8') as f:
    # f.write('擦勒\n')
 
# 强调1:
# 在以w模式打开文件没有关闭的情况下,连续写入,新的内容总是跟在旧的之后
# with open('d.txt',mode='wt',encoding='utf-8') as f:
#     f.write('1\n')
#     f.write('2\n')
#     f.write('3\n')
 
# 强调2:
# 如果重新以w模式打开文件,则会清空文件内容
# with open('d.txt',mode='wt',encoding='utf-8') as f:
#     f.write('擦勒1\n')
# with open('d.txt',mode='wt',encoding='utf-8') as f:
#     f.write('擦勒2\n')
# with open('d.txt',mode='wt',encoding='utf-8') as f:
#     f.write('擦勒3\n')
 
#创建新文件,并读取
# src_file=input('源文件路径>>: ').strip()
# dst_file=input('源文件路径>>: ').strip()
# with open(r'{}'.format(src_file),mode='rt',encoding='utf-8') as f1,\
#     open(r'{}'.format(dst_file),mode='wt',encoding='utf-8') as f2:
#     res=f1.read()
#     f2.write(res)
 
 
# 3、a:只追加写,在文件不存在时会创建空文档,在文件存在时文件指针会直接调到末尾
# with open('e.txt',mode='at',encoding='utf-8') as f:
#     # f.read() # 报错,不能读
#     f.write('11\n')
#     f.write('22\n')
#     f.write('33\n')
 
# 强调 w 模式与 a 模式的异同:
# 1 相同点:在打开的文件不关闭的情况下,连续的写入,新写的内容总会跟在前写的内容之后
# 2 不同点:以 a 模式重新打开文件,不会清空原文件内容,会将文件指针直接移动到文件末尾,新写的内容永远写在最后
 
 
# 案例:a模式用来在原有的文件内存的基础之上写入新的内容,比如记录日志、注册
# 注册功能
# name=input('your name>>: ')
# pwd=input('your name>>: ')
# with open('db.txt',mode='at',encoding='utf-8') as f:
#     f.write('{}:{}\n'.format(name,pwd))
 
 
# 了解:+不能单独使用,必须配合r、w、a
# with open('g.txt',mode='rt+',encoding='utf-8') as f:
#     # print(f.read())
#     f.write('中国')
 
# with open('g.txt',mode='w+t',encoding='utf-8') as f:
#     f.write('111\n')
#     f.write('222\n')
#     f.write('333\n')
#     print('====>',f.read())
 
#
# with open('g.txt',mode='a+t',encoding='utf-8') as f:
#     print(f.read())
#     f.write('444\n')
#     f.write('5555\n')
#     print(f.read())                   

  6、文件操作方法

f.read() #读取所有内容,光标移动到文件末尾
f.readline() #读取一行内容,光标移动到第二行首部 ,一次读一行
f.readlines() #读取每一行内容,存放于列表中

f.write('1111\n222\n') #针对文本模式的写,需要自己写换行符
f.write('1111\n222\n'.encode('utf-8')) #针对b模式的写,需要自己写换行符
f.writelines(['333\n','444\n']) #文件模式
f.writelines([bytes('333\n',encoding='utf-8'),'444\n'.encode('utf-8')]) #b模式


f.readable() #文件是否可读
f.writable() #文件是否可读
f.closed #文件是否关闭
f.encoding #如果文件打开模式为b,则没有该属性
f.flush() #立刻将文件内容从内存刷到硬盘
f.name

  7、文件光标的移动

    7.1: read(3):

      1. 文件打开方式为文本模式时,代表读取3个字符

      2. 文件打开方式为b模式时,代表读取3个字节

         7.2: 其余的文件内光标移动都是以字节为单位如seek,tell,truncate(截断)

    注意:

      1. seek有三种移动方式0,1,2,其中1和2必须在b模式下进行,但无论哪种模式,都是以bytes为单位移动的

#f.seek(n,模式):n指的是移动的字节个数
# 模式:
# 模式0:参照物是文件开头位置
# f.seek(9,0)
# f.seek(3,0) # 3
 
# 模式1:参照物是当前指针所在位置
# f.seek(9,1)
# f.seek(3,1) # 12
 
# 模式2:参照物是文件末尾位置,应该倒着移动
# f.seek(-9,2) # 3
# f.seek(-3,2) # 9
 
# 强调:只有0模式可以在t下使用,1、2必须在b模式下用

      2.f.tell() # 获取文件指针当前位置

with open('aaa.txt',mode='rb') as f:
#     f.seek(9,0)
#     f.seek(3,0) # 3
#     # print(f.tell())
#     f.seek(4,0)
#     res=f.read()
#     print(res.decode('utf-8'))

      3. truncate是截断文件,所以文件的打开方式必须可写,但是不能用w或w+等方式打开,因为那样直接清空文件了,所以truncate要在r+或a或a+等模式下测试效果

    例子:

with open (r'E:\PY\venv\01.txt',encoding='utf-8',mode='rt') as f:  # 在rt模式下 read内的数字 表示的是字符的个数
    print(f.read(11))
with open(r'E:\PY\venv\01.txt', encoding='utf-8', mode='rb') as f:
    ser=f.read(11)  # rb 模式读取的是字节数 
    print(ser)
    # print(ser.decode('utf-8'))
    # f.seek(offset.whence)
    # offset:相对偏移量,光标的移动位数.相对偏移量可以为负数,代表从文末开始读取。为正数时代表从文始开始读取
    # whence:'0,1,2'
    #  0:参照文件的开头 t和b 都可以使用
    #  1:参照光标所在的当前位置 只能在b模式下用
    #  2: 参照文件末尾 只能在b模式下使用
with open (r'E:\PY\venv\01.txt',mode='rb') as f: 不需要转成 encoding='utf-8'
    print(f.read(1))
    set=f.seek(6,0)     # 一个文字对应3个字节,一个英文对应一个字节
    print(set)
    print(f.seek(6,0))  #rb模式下的都是移动字节数,出了r模式外
    print(f.seek(0,0))
    print(f.read(1))
   print(f.seek(-4,1))

#添加文件
with open(r'test','r+',encoding='utf-8') as f:
  #     f.seek(6,0)
  #     f.write('过'),在第6个字符后面加"过"

  8、文件修改:

'''
方式一:
1.先将数据由硬盘读到内存(读文件)
2.在内存中完成修改(字符串的替换)
3.再覆盖原来的内容(写文件)
'''
with open(r'test02.txt','w',encoding='utf-8') as f:
     res = data.replace('egon','jason')  # 直接替换
     print(data)
     f.write(res)
#优点:任意时间硬盘上只有一个文件 不会占用过多硬盘空间
#缺点:当文件过大的情况下,可能会造成内存溢出


'''
方式二
# 创建一个新文件
# 循环读取老文件内容到内存进行修改  将修改好的内容写到新文件中
# 将老文件删除  将新文件的名字改成老文件名
'''
import os
with open(r'test02.txt','r',encoding='utf-8') as read_f,\
        open(r'test02.swap','a',encoding='utf-8') as write_f:
    for line in read_f:
        new_line = line.replace('jason','egon')
        write_f.write(new_line) ## 添加新内容
os.remove('test02.txt')
os.rename('test02.swap','test02.txt')  ## 重命名
#优点:内存中始终只有一行内容 不占内存
#缺点:再某一时刻硬盘上会同时存在两个文件

 

补充:文件模式之x模式

x模式(控制文件操作的模式)-》了解
    x, 只写模式【不可读;不存在则创建,存在则报错】
"""
# with open('a.txt',mode='x',encoding='utf-8') as f:
#     pass
 
# with open('c.txt',mode='x',encoding='utf-8') as f:
#     f.read()
 
with open('d.txt', mode='x', encoding='utf-8') as f:
    f.write('哈哈哈\n')

  

  文件拷贝工具:减少内存占用

src_file=input('源文件路径>>: ').strip()
dst_file=input('源文件路径>>: ').strip()
with open(r'{}'.format(src_file),mode='rb') as f1,\
    open(r'{}'.format(dst_file),mode='wb') as f2:
    # res=f1.read() # 内存占用过大
    # f2.write(res)
 
    for line in f1:
        f2.write(line)

 

  循环读取文件:两种方式

#方式一:自己控制每次读取的数据的数据量
# with open(r'test.jpg',mode='rb') as f:
#     while True:
#         res=f.read(1024) # 1024
#         if len(res) == 0:
#             break
#         print(len(res))
 
 
# 方式二:以行为单位读,当一行内容过长时会导致一次性读入内容的数据量过大
# with open(r'g.txt',mode='rt',encoding='utf-8') as f:
#     for line in f:
#         print(len(line),line)
 
# with open(r'g.txt',mode='rb') as f:
#     for line in f:
#         print(line)
 
# with open(r'test.jpg',mode='rb') as f:
#     for line in f:
#         print(line)

 

posted @ 2022-03-26 22:36  新入世界的小白  阅读(457)  评论(0编辑  收藏  举报