编码解码与文件操作

一、二进制和编码表

1.二进制

计算机只能够识别数字0和1。因此,二进制就是计算机唯一可以识别的进位制,每个二进制数都只包含数字0和1。在计算机中,用来存放一个0或者1的位置,就是计算机中最小的储存单位,叫做位,外国名字叫bit,也叫做比特。我们规定8个比特构成一个字节(byte),字节是计算机里最常用的单位。
计算机的常用单位换算:
1B=8bit
1KB=1024B
1MB=1024KB
1GB=1024MB
1T=1024GB

2.编码表

前文提到,计算机只能识别数字0和1。那么计算机想要识别输入的内容以及想要输出内容,就需要用二进制数与这些内容进行转化,转化的依据即为编码表。在编码表中,每个有实际意义的符号,数字,字母等都会有唯一的二进制数与之对应。但编码表并不唯一,其种类有很多。
下面,我们详细介绍几种常见的编码表:

编码表适用性特点
ASK II码英文大小写,字符,不支持中文由美国人发明,涵盖内容较少
GBK、GB2312码支持了中文中国人发明,GB2312码为加强版的GBK码
Unicode码支持国际语言适用性强,但占用空间大。这种编码方式所对应的每个元素被编码后所需的存储空间都比ASK II码多出8个bit位
UTF-8码支持国际语言升级版的Unicode码,占用空间减小,并且这两种方式非常容易转化

二、编码与解码

在之前的讲述中,我们知道我们需要依据编码表才能将我们想输入的内容转化成计算机能识别的二进制数让计算机接收,这个过程叫做编码。同样,计算机输出的二进制数也需要通过编码表才能转换成我们可以识别的信息,这个转化过程就叫做解码。上文介绍过,编码表并不唯一,因此每种编码表对应的编码与解码方式也各有不同。所以如果编码或解码过程使用不同的编码表会造成乱码。
编码和解码在程序运行时会自动进行。下面,我们讲述如何查看计算机的编码与解码过程:

1.编码

我们想要查看向计算机输入的人类语言是如何转化成二进制数编码,可以使用encode()函数,用法如下:

print('人类的语言'.encode('想使用的编码表'))

这样,我们就可以看到使用某种编码表对人类语言进行编码时,计算机接收到的内容(为了节省空间,的终端会以16进制数的形式输出)。例:

print('查看编码解码'.encode('GBK'))
print('查看编码解码'.encode('utf-8'))
#输出为:b'\xb2\xe9\xbf\xb4\xb1\xe0\xc2\xeb\xbd\xe2\xc2\xeb'
#        b'\xe6\x9f\xa5\xe7\x9c\x8b\xe7\xbc\x96\xe7\xa0\x81\xe8\xa7\xa3\xe7\xa0\x81'

其中,“\x”表示结果以16进制数表示,两位的16进制数需要的空间为8个bit位。

2.解码

同样的,我们想要查看解码过程可以使用decode()函数,用法如下:

print(计算机二进制编码.decode('想使用的编码表'))

下面以之前的输出结果为例,了解计算机解码过程:

print(b'\xb2\xe9\xbf\xb4\xb1\xe0\xc2\xeb\xbd\xe2\xc2\xeb'.decode('GBK'))
print(b'\xe6\x9f\xa5\xe7\x9c\x8b\xe7\xbc\x96\xe7\xa0\x81\xe8\xa7\xa3\xe7\xa0\x81'.decode('utf-8'))
#输出为:查看编码解码
#        查看编码解码

3.统一编码和解码所使用的编码表的重要性

下面我们探讨,假如我们选错了编码表,会有什么样的事情发生:

print(b'\xe6\x9f\xa5\xe7\x9c\x8b\xe7\xbc\x96\xe7\xa0\x81\xe8\xa7\xa3\xe7\xa0\x81'.decode('GBK'))
# 人类语言“查看编码解码”以UTF-8码进行编码,以GBK码进行译码

# 输出为:鏌ョ湅缂栫爜瑙g爜

如果编码时使用的编码表每个元素对应的bit位少(如使用GBK码),而译码时使用的编码表每个元素对应的bit位多(如使用UTF-8码),将会引起计算机报错:

print(b'\xb2\xe9\xbf\xb4\xb1\xe0\xc2\xeb\xbd\xe2\xc2\xeb'.decode('UTF-8'))

在之后的文件操作以及利用Python发送邮件,都需要使用合适的编码表。因此,操作.txt文档或.csv表格时,如果输出为乱码时,应该检查计算机的编码方式是否出现问题。可以参考以下内容:
pycharm怎么设置文件编码

三、.txt文件的操作

下面讲述通过Python语言如何进行文件操作。Python语言可以操作计算机中的文件,可以读取写入文本内容、音频、表格、邮件等内容。下面我们学习用Python语言对.txt文本的部分操作:
对文档的操作基本流程为:打开文件——操作文件——关闭文件。在文件操作之中,常用到的函数有:

自定义变量名=open(r'文件名.txt','mode参数',encoding='使用的编码表') # 打开文档。encoding是默认参数。
自定义变量名.read() # 读取文档
自定义变量名.write('需要写入的内容')
自定义变量名.close() # 关闭文档

在完成对文件进行的操作之后,必须使用close()函数进行关闭文件,否则文建会一直处于打开的状态。如果操作的文件数很多,不能及时关闭文件会降低电脑的运行速度。
常见的几种模式(基础):

模式参数功能
‘r’(读取模式)指定文件必须存在,指针放于文档开头,可以配合read()函数进行一次文件读取,读取完成后指针会置于文档末尾。
‘w’(只写模式)可以配合write()函数写入内容。这种模式下,如果指定文件存在会清空文件内容再写入新内容,如果指定文件不存在则会新建文件并写入内容。
‘a’(追加模式)指定文件如存在,指针会放在末尾,可以追加写入内容。如果指定文件不存在则会新建文件。

1. .txt文件的读取

下面,我们尝试一下基本的文件操作。首先,找到pycharm中.py文件的存放位置,然后新建一个.txt文件,并写入内容,暂时将其命名为one:
在这里插入图片描述
这就是我们创建的新文件,下面我们在pycharm中对它进行操作:

myfile=open(r'one.txt','r')
content=myfile.read()
print(content)
print(myfile)
# open()函数会返回文件名,模式参数和编码方式
myfile.close()
# 运行结果为:我就是我,
#             不一样的烟火
#             <_io.TextIOWrapper name='one.txt' mode='r' encoding='cp936'>

由以上结果可以发现,read()的返回值为文档的内容。
由于使用read()函数后,读取文档内容之后指针也会相应地移动到末尾,所以再次使用read()函数,将不会再输出文档内容:

myfile=open(r'one.txt','r')
print(myfile.read())
print('---------divide----------')
print(myfile.read())
myfile.close()
# 输出结果为:我就是我,
#             不一样的烟火
#             ---------divide----------
#

需要注意的是,以’r’模式打开指定文件,要求该文件必须存在,否则就会报错。很多电脑是默认隐藏文件扩展名的,给大家参考一种显示拓展名的方法:怎样显示文件扩展名即后缀

2. .txt文件的写模式

通过之前的介绍,我们认识了w模式和a模式,这两种模式都可以针对.txt文件写入内容,下面,我们先来具体探讨’w’模式

2.1 'w’模式下指定文件不存在时的情况

首先,我们确保路径下没有one.txt文档,观察以下代码:

myfile=open(r'one.txt','w')
content=myfile.write('我就是我,\n不一样的烟火')
myfile.close()

这段代码可以正常运行,但不会输出结果,但我们回到之前的路径,会发现一个名为one.txt的文件,打开之后的内容为:
在这里插入图片描述
不难发现,当时用’w’模式打开文件时,如果之前不存在该文件则会自动创建文件,并可以进行内容的写入。

2.2 'w’模式下指定文件存在时的情况

myfile=open(r'one.txt','w')
content=myfile.write('愿你出走半生,\n归来仍是少年')
print(content)
myfile.close()
# 输出结果为:14

通过输出的结果我们不难发现,write()函数的返回值为其位置参数的字符数对应的字符数(在默认的编码方式之下,单个的汉字、字母、标点和输出表达符等,都算1个字符,占据2字节的空间)。随后,我们打开one.txt文件进行查看:
在这里插入图片描述
可以看到,我们已经完成了内容的写入内容,但原本的内容已经被全部覆盖,即使写入的内容比原有内容短,'w’模式下write()函数仍然会清空所有内容再进行写入。
注:①使用write()函数进行写操作时,只能写入str类型的内容,否则会报错;
②pycharm执行write()函数时,可能按GBK编码,因此如果在中文字符(2字节)中夹杂着英文标点(1字节),将会引起计算机报错。
现在,我们探讨一下在’w’模式下使用两次write()函数会有怎样的情况发生:

myfile=open(r'one.txt','w')
myfile.write('愿你出走半生,\n归来仍是少年')
myfile.write('我就是我,\n,不一样的烟火')
myfile.close()

打开文件查看内容:
在这里插入图片描述
可以看到,第二次的write()函数并没有清空文件重新写入,而是在文件的末尾追加了要写的内容。
我们在观察以下代码:

myfile=open(r'one.txt','w')
myfile.close()
myfile=open(r'one.txt','r')
print(myfile.read())
myfile.close()
# 输出结果为:

可以看到,运行之后,原本存有内容的one.txt文档变成了空文档。因此我们知道,清空文档是open()函数在以’w’模式打开文件时完成的,而并非执行write()函数时才完成。

2.3 'a’模式

'a’模式可以在原有内容的基础上,在文档的末尾追加写入内容而不会覆盖原有内容。除此之外,与’w’模式比较类似,这种模式下同样不能进行读取操作,并且如果路径下没有该文件则会自动新建。

# 将之前的one.txt文件删掉,重新进行运行测试:
myfile=open(r'one.txt','a')
content=myfile.write('\n我就是我,\n不一样的烟火')
myfile.close()

运行结束后,终端同样没有内容,但我们找到对应的路径,发现了one.txt文件:
在这里插入图片描述
现在,路径下已经有了one.txt的文件,我们再运行一次上面的代码,看看文档会有什么变化:
在这里插入图片描述

3. 模式参数强化版介绍

以上我们介绍了最常见的模式,下面我们简要介绍这些模式的强化版:

模式参数功能
‘r+’(读取模式强化版)在’r’模式的基础上支持写,可以配合write()函数使用。
‘w+’ (写模式强化版)在’w’模式的基础上支持了读,可以配合read()函数使用,但一般无法读出内容。
‘a+’ (追加模式强化版)在’a’模式的基础上支持了读,可以通过修改指针位置达到从指定位置读取的功能,但依旧只能从文档末尾追加内容。
‘rb’/‘rb+’与’r’/'r+'类似,区别为它是基于二进制的只读/读写
‘wb’/‘wb+’与’w’/'w+'类似,区别为它是基于二进制的只写/读写
‘ab’/‘ab+’与’a’/'a+'类似,区别为它是基于二进制的追加/可读且可追加

下面我们详细分析这些参数功能有了怎样的强化。

3.1 'r+'模式参数

以下会通过分析实例解析’r+'模式带来的改变。方便起见,使用2.3处编辑好的文件进行演示。

f= open(r'one.txt','r+')
f_read=f.read()
print(f_read)
f.close()
# 输出为:
#        我就是我,
#        不一样的烟火
#        我就是我,
#        不一样的烟火

可以看到,读取功能与’r’模式下一样。

f= open(r'one.txt','r+')
f_write=f.write('愿你出走半生,\n归来仍是少年\n')
f_read=f.read()
print(f_read)
f.close()
# 输出为:就是我,
#         不一样的烟火

而此时打开文件,查看结果为:
在这里插入图片描述
分析一下出现以下结果的原因:
计算机识别到的文件的内容最开始为:\n我就是我,\n不一样的烟火\n我就是我,\n不一样的烟火
'r+'模式打开文档时,指针是在文档的最前的。因此write()函数写入的 愿你出走半生,\n归来仍是少年\n
会从前向后逐个覆盖掉之前的文档内容(“\n”占两个字节),覆盖之后,文档的内容为:愿你出走半生,\n归来仍是少年\n就是我,\n不一样的烟火
因此打开文件之后也就是我们文档中显示的样子了。而我们通过read()函数读取,由于指针已经向后移动,所以不能读取全部的文档内容了。
下面我们将文档内容改为本节开始时的内容,运行下面代码:

f= open(r'one.txt','r+')
f_read=f.read()
print(f_read)
f_write=f.write('愿你出走半生,\n归来仍是少年\n')
print('\n--------defence---------')
f_read=f.read()
print(f_read)
f.close()
# 输出为:
#        我就是我,
#        不一样的烟火
#        我就是我,
#        不一样的烟火
#
#        --------defence---------
#

打开文件查看到结果为:
在这里插入图片描述
可以看到我们先查看内容人后再写入内容,就是从文档的最末尾处写入了。出现这样结果的原因,还是由于执行read()函数之后,指针指向已经从文档最开始的位置指向了最后的位置,所以再写入内容,就是在文档末尾添加了。而由于执行完read()函数和write()函数之后,指针依然在这个文档的末尾,所以此时再执行一次read()函数将不能读取到任何内容。这种操作在添加内容的位置上看,有点像’a’模式。

3.2 'w+'模式参数

'w+'模式相对比较简单,它在’w’模式的基础上支持了读模式,但使用’w+'模式的open()函数和’w’模式一样,如果文件存在会清空文件内容,不存在则会新建文件,所以尽管支持读模式,依然无法读取到任何内容。

f= open(r'one.txt','w+') # one.txt文档原本存有内容
f_read=f.read()
print(f_read)
f_write=f.write('愿你出走半生,\n归来仍是少年\n')
f_read=f.read()
print(f_read)
f.close()
# 输出为:
#        

先写后读,依然读不到内容,原因与上文相似,指针位置还是指向文档末尾。
此时的one.txt文件内容为:
在这里插入图片描述

3.3 'a+'模式参数

'a+'模式也非常简单,为可读的追加模式,由于指针默认放在文档的最后,因此尽管在使用open()函数时文档没被清空,但依然没办法用read()函数读到文档内容。参考以下示例:

f= open(r'one.txt','a+')
f_read=f.read()
print(f_read)
f_write=f.write('\n这里使用的文档,内容是上一节写入的')
f_read=f.read()
print(f_read)
f.close()
# 输出为:
#

运行之后,文档的内容为:
在这里插入图片描述

4.神奇的辅助函数

以上,我们介绍了三个常用强化模式的基本用法,但我们发现,好多我们希望的功能通过强化模式依然无法实现。因为指针的位置经常不在我们想让他在的地方。假如我们可以任意移动指针的位置,强化模式参数的功能才可以更好的体现。这时,一个强有力的,可以按照我们的需要调整指针位置的辅助函数seek()便映入了我们的眼帘。

4.1 seek()配合’r+'模式参数

在3.1节里,我们提到了模式参数’r+'只能读取一次文档内容,只能在文档开头覆写内容,覆写之后只能查看当前指针位置后面的内容,但这些问题都随着seek()函数的出现得以解决:

f= open(r'one.txt','r+')
print(f.read())
f.seek(4)
print("------------------------")
print(f.read())
# 可以读取两次,并且可以在任意位置开始读取
print("------------------------")
f.seek(14)
f_write=f.write('不一样的烟火')
# 可以在任意位置覆写
f.seek(0)
print(f.read())
# 可以直接在终端查看内容是否正确,无需打开文件
f.close()
# 输出为:愿你出走半生,
#         归来仍是少年
# 
#         这里使用的文档,内容是上一节写入的
# 
#         ------------------------
#         出走半生,
#         归来仍是少年
# 
#         这里使用的文档,内容是上一节写入的
# 
#         ------------------------
#         愿你出走半生,不一样的烟火年
# 
#         这里使用的文档,内容是上一节写入的

功能一下子就强大了很多。
注:seek()函数里第一个位置参数代调整后表指针所在位置的字节数,因此必须填入偶数,否则会引发报错。具体原因详见3.1节

4.2 seek()配合’w+'模式参数

因为模式参数’w+'在’w’的基础上增加了读模式,因此我们主要希望可以实现在写入后可以从任意位置进行查看:

f= open(r'one.txt','w+')
f.write('愿你出走半生,\n归来仍是少年')
f.seek(4)
f_read=f.read()
print(f_read)
f.close()
# 输出为:出走半生,
#        归来仍是少年

4.3 seek()配合’a+'模式参数

这里需要注意一点,尽管seek()函数可以改变指针位置,'a+'模式参数依然只能实现在文档末尾添加内容。

f= open(r'one.txt','a+')
f.seek(2)
f_read=f.read()
print(f_read)
f.seek(2)
f_write=f.write('\n文档继续承接上文使用')
# 这句话依然添加到了文档末尾
print('-----------------------')
f.seek(0)
print(f.read())
f.close()
# 输出为:你出走半生,
#        归来仍是少年
#        -----------------------
#        愿你出走半生,
#        归来仍是少年
#        文档继续承接上文使用

可以看出,有了seek()函数的辅助,文档处理起来就轻松了很多。此外,seek()函数也可以配合普通版的模式参数使用,用法类似。有兴趣的小伙伴可以自行尝试。

5. .txt文件的自动关闭

之前提到过,打开的文件必须在操作完成之后关闭,否则会指战员计算机内存,严重时会造成卡顿。但是粗心的小伙伴经常会忘记最后加上close()函数,因此为大家介绍一种一定会关闭文件的操作方式:
使用with方法打开文件,可以不需要close()函数也能在操作完文件后自动予以关闭。其格式如下:

with open(r'one.txt','a+') as f:
    f.seek(2)
    f_read=f.read()
    print(f_read)
# 输出为:你出走半生,
#         归来仍是少年
#         文档继续承接上文使用

这期的分享到此结束,喜欢的小伙伴欢迎点赞支持一下~

  • 16
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值