zoukankan      html  css  js  c++  java
  • 文件处理

    一、字符编码

    1.1计算机基础

    1. CPU:控制程序的运行(从内存中取出文本编译器的数据读入内存)

    2. 内存:运行程序(经CPU操作后,内存中含有文本编译器的数据)

    3. 硬盘:存储数据(文本编译器)

    1.2文本编译器存取文件的原理

    1. 打开编译器就打开了启动了一个进程,是在内存中的,所以,用编译器编写的内容也都是存放与内存中的,断电后数据丢失。

    2. 文本编译器的作用:读取数据,保存数据

      • 第一阶段:Python解释器启动,此时就相当于启动了一个文本编译器

      • 第二阶段:Python解释器相当于文本编译器,去打开test.py文件,从硬盘上将test.py的文件内容读入到内存中。

      • 第三阶段:Python解释器解释执行刚刚加载到内存中的test.py的代码。(ps:在该阶段,即真正执行代码时,才会识别Python的语法,

    1.3Python解释器执行py文件的原理

    • 第一阶段:Python解释器启动,此时就相当于启动了一个文本编辑器

    • 第二阶段:Python解释器相当于文本编辑器,去打开test.py文件,从硬盘上将test.py的文件内容读入到内存中(小复习:pyhon的解释性,决定了解释器只关心文件内容,不关心文件后缀名)。

    • 第三阶段:Python解释器解释执行刚刚加载到内存中test.py的代码( ps:在该阶段,即真正执行代码时,才会识别Python的语法,执行文件内代码,当执行到name="egon"时,会开辟内存空间存放字符串"egon")。

    1.4 Python解释器与文本编译的异同

    • 相同点:Python解释器是解释执行文件内容的,因而Python解释器具备读py文件的功能,这一点与文本编辑器一样。

    • 不同点:文本编辑器将文件内容读入内存后,是为了显示或者编辑,根本不去理会Python的语法,而Python解释器将文件内容读入内存后,可不是为了给你瞅一眼Python代码写的啥,而是为了执行Python代码、会识别Python语法。

    1.5 字符编码介绍

    1.5.1 什么是字符编码

    定义:二进制和你所能认识的字符之间的相互转化的一个过程

    总而言之,字符编码是将人类的字符编码成计算机能识别的数字,这种转换必须遵循一套固定的标准,该标准无非是人类字符与数字的对应关系,称之为字符编码表。

    1.5.2 涉及到字符编码的两个场景

    1. 一个Python文件中的内容是由一堆字符组成的,存取均涉及到字符编码问题(Python文件并未执行,前两个阶段均属于该范畴)。

    2. Python中的数据类型字符串是由一串字符组成的(Python文件执行时,即第三个阶段)。

    1.5.3 字符编码发展史与分类

    计算机由美国人发明,最早的字符编码为ASCII,只规定了英文字母数字和一些特殊字符与数字的对应关系。最多只能用 8 位来表示(一个字节),即:2**8 = 256,所以,ASCII码最多只能表示 256 个符号。

    046-字符编码-ASCII表.jpg?x-oss-process=style/watermark

    当然我们编程语言都用英文没问题,ASCII够用,但是在处理数据时,不同的国家有不同的语言,中国人会加入中文,日本人会在自己的程序中加入日文,韩国人也是。

    但是要表示中文,单拿一个字节表表示一个汉子,是不可能表达完的(连小学生都认识两千多个汉字),解决方法只有一个,就是一个字节用>8位2进制代表,位数越多,代表的变化就多,这样,就可以尽可能多的表达出不通的汉字。

    所以中国人规定了自己的标准gb2312编码,规定了包含中文在内的字符与数字的对应关系。

    日本人规定了自己的Shift_JIS编码;韩国人规定了自己的Euc-kr编码(另外,韩国人说,计算机是他们发明的,要求世界统一用韩国编码,但世界人民没有搭理他们)。

    046-字符编码-总结字符编码发展史.png?x-oss-process=style/watermark

    这时候问题出现了,精通18国语言的小周同学谦虚的用8国语言写了一篇文档,那么这篇文档,按照哪国的标准,都会出现乱码(因为此刻的各种标准都只是规定了自己国家的文字在内的字符跟数字的对应关系,如果单纯采用一种国家的编码格式,那么其余国家语言的文字在解析时就会出现乱码)。所以迫切需要一个世界的标准(能包含全世界的语言)于是Unicode应运而生(韩国人表示不服,然后没有什么卵用)。

    ascii用1个字节(8位二进制)代表一个字符;Unicode常用2个字节(16位二进制)代表一个字符,生僻字需要用4个字节。

    例:字母x,用ascii表示是十进制的120,二进制0111 1000。

    汉字中已经超出了ASCII编码的范围,用Unicode编码是十进制的20013,二进制的01001110 00101101。

    字母x,用Unicode表示二进制0000 0000 0111 1000,所以Unicode兼容ascii,也兼容万国,是世界的标准。

    这时候乱码问题消失了,所有的文档我们都使用但是新问题出现了,如果我们的文档通篇都是英文,你用Unicode会比ascii耗费多一倍的空间,在存储和传输上十分的低效。

    本着节约的精神,又出现了把Unicode编码转化为“可变长编码”的UTF-8(Unicode Transformation Format-8)编码。UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。如果你要传输的文本包含大量英文字符,用UTF-8编码就能节省空间:

    字符ASCIIUnicodeUTF-8
    A 01000001 00000000 01000001 01000001
    x 01001110 00101101 11100100 10111000 10101101

    从上面的表格还可以发现,UTF-8编码有一个额外的好处,就是ASCII编码实际上可以被看成是UTF-8编码的一部分,所以,大量只支持ASCII编码的历史遗留软件可以在UTF-8编码下继续工作。

    1.5.4内存为什么不用UTF-8呢?

    说了那么一大堆,那为什么内存用Unicode,而不直接使用UTF-8呢?这样不就可以直接把代码从内存直接丢入硬盘了吗?出现这个问题的原因是硬盘中还躺了其他国家的代码,各个国家的代码的二进制还需要运行在计算机上使用,因此内存中必须使用Unicode的编码,因为Unicode能和硬盘中其他国家的二进制中的代码进行转换,但是UTF-8只是简化了代码的存储,它并不能与其他国家硬盘中的代码进行关系转换。总而言之只有Unicode编码才能运行其他国家硬盘中的代码,而UTF-8的代码无法进行该操作。

    内存中还使用Unicode编码,是因为历史遗留问题造成的,但是因为现在写代码使用的都是UTF-8代码,所以以后内存中的代码都将变成UTF-8代码,并且以前遗留的各个国家的代码都将被淘汰,所以未来内存中使用的编码也将使用UTF-8编码替代Unicode编码。

    1.5.5 字符编码之文本编译器操作

    046-字符编码-文本编辑器1.png?x-oss-process=style/watermark

    046-字符编码-文本编辑器2.png?x-oss-process=style/watermark

    046-字符编码-文本编辑器3.png?x-oss-process=style/watermark

    046-字符编码-文本编辑器4.png?x-oss-process=style/watermark

    1.5.6 乱码分析

    首先明确概念

    • 文件从内存刷到硬盘的操作简称存文件

    • 文件从硬盘读到内存的操作简称读文件

    乱码的两种情况:

    • 乱码一:存文件时就已经乱码

    存文件时,由于文件内有各个国家的文字,我们单以shiftjis去存, 本质上其他国家的文字由于在shiftjis中没有找到对应关系而导致存储失败。但当我们硬要存的时候,编辑并不会报错(难道你的编码错误,编辑器这个软件就跟着崩溃了吗???),但毫无疑问,不能存而硬存,肯定是乱存了,即存文件阶段就已经发生乱码,而当我们用shiftjis打开文件时,日文可以正常显示,而中文则乱码了。

    • 乱码二:存文件时不乱码而读文件时乱码

    存文件时用utf-8编码,保证兼容万国,不会乱码,而读文件时选择了错误的解码方式,比如gbk,则在读阶段发生乱码,读阶段发生乱码是可以解决的,选对正确的解码方式就ok了。

    1.6总结

    1. 保证不乱码的核心法则就是,字符按照什么标准而编码的,就要按照什么标准解码,此处的标准指的就是字符编码。

    2. 在内存中写的所有字符,一视同仁,都是Unicode编码,比如我们打开编辑器,输入一个“你”,我们并不能说“你”就是一个汉字,此时它仅仅只是一个符号,该符号可能很多国家都在使用,根据我们使用的输入法不同这个字的样式可能也不太一样。只有在我们往硬盘保存或者基于网络传输时,才能确定”你“到底是一个汉字,还是一个日本字,这就是Unicode转换成其他编码格式的过程了。简而言之,就是内存中固定使用的就是Uncidoe编码,我们唯一能改变的就是存储到硬盘时使用的编码。

    • Unicode----->encode(编码)-------->gbk

    • Unicode<--------decode(解码)<----------gbk

    046-字符编码-utf8与Unicode转换.png?x-oss-process=style/watermark

     

    二、Python2和3字符编码的区别

    2、1 字符编码应用之Python

    2、1、1 执行Python程序的三个阶段

    Python test.py(我再强调一遍,执行test.py的第一步,一定是先将文件内容从硬盘读入到内存中)

    test.py文件内容以gbk格式保存的,内容为:

    047-Python2与3字符编码的区别-代码编写.png?x-oss-process=style/watermark

    • 阶段一:启动Python解释器

    • 阶段二:Python解释器此时就是一个文本编辑器,负责打开文件test.py,即从硬盘中读取test.py的内容到内存中

    此时,Python解释器会读取test.py的第一行内容,#coding:utf-8#-*-coding:utf-8-*-,以此决定以什么编码格式将代码读入内存,这一行就是设定Python解释器这个软件使用的编码格式。

    可以用sys.getdefaultencoding()查看,如果不在Python文件指定头信息#-*-coding:utf-8-*-,那就使用Python默认的编码格式。

    import sys

    sys.getdefaultencoding()
    'utf-8'

    Python2中默认使用ascii,Python3中默认使用utf-8。

    047-Python2与3字符编码的区别-语法报错.png?x-oss-process=style/watermark

    改正:在test.py指定文件头,字符编码一定要为gbk。即更正为

    #coding:gbk
    你好啊

    047-Python2与3字符编码的区别-修正.png?x-oss-process=style/watermark

    • 阶段三:读取已经加载到内存的代码(Unicode编码格式),然后执行,执行过程中可能会开辟新的内存空间,比如name="nick"

    内存的编码使用Unicode,不代表内存中全都是Unicode,因为在程序执行之前,内存中确实都是Unicode,比如从文件中读取了一行name="nick",其中的name、等号、引号的地位都一样,都是普通字符而已,都是以Unicode的格式存放于内存中的。

    但是程序在执行过程中,会申请内存(与程序代码所存在的内存是俩个空间)用来存放Python的数据类型的值,而Python的字符串类型又涉及到了字符的概念。

    比如name="nick",会被Python解释器识别为字符串,会申请内存空间来存放字符串类型的值,至于该字符串类型的值被识别成何种编码存放,这就与Python解释器的有关了,而Python2与Python3的字符串类型又有所不同。

    2、2 Python2与Python3字符串类型的区别

    2、2、1 Python2

    在Python2中有两种字符串类型str和Unicode。

    1 str 类型

    当Python解释器执行到产生字符串的代码时(例如x='上'),会申请新的内存地址,然后将'上'编码成文件开头指定的编码格式

    因为直接print()会自动转换编码,我们使用encode()方法查看'上'的字符编码。

    # 三、Python2中代码

    # 四、coding:gbk

    x = '上'
    y = '下'
    print([x, y])  # ['xc9xcf', 'xcfxc2']
    # 五、x代表16进制,此处是c9cf总共4位16进制数,一个16进制四4个比特位,4个16进制数则是16个比特位,即2个Bytes,这就证明了按照gbk编码中文用2Bytes

    print(type(x),type(y))  # (<type 'str'>, <type 'str'>)

    理解字符编码的关键!!!

    内存中的数据通常用16进制表示,2位16进制数据代表一个字节,如xc9,代表两位16进制,一个字节

    gbk存中文需要2个bytes,而存英文则需要1个bytes,它是如何做到的???!!!

    gbk会在每个bytes,即8位bit的第一个位作为标志位,标志位为1则表示是中文字符,如果标志位为0则表示为英文字符。

    x='你a好'`
    转成gbk格式二进制位:`8bit+8bit+8bit+8bit+8bit=(1+7bit)+(1+7bit)+(0+7bit)+(1+7bit)+(1+7bit)

    这样计算机按照从左往右的顺序读:

    1. 连续读到前两个括号内的首位标志位均为1,则构成一个中午字符:你

    2. 读到第三个括号的首位标志为0,则该8bit代表一个英文字符:a

    3. 连续读到后两个括号内的首位标志位均为1,则构成一个中午字符:好

    也就是说,每个Bytes留给我们用来存真正值的有效位数只有7位,而在Unicode表中存放的只是这有效的7位,至于首位的标志位与具体的编码有关,即在Unicode中表示gbk的方式为:(7bit)+(7bit)+(7bit)+(7bit)+(7bit)

    047-Python2与3字符编码的区别-gbk上.png?x-oss-process=style/watermark

    按照上图翻译的结果,我们可以去Unicode关于汉字的对应关系中去查:链接:https://pan.baidu.com/s/1dEV3RYp

    可以看到“上”对应的gbk(G0代表的是gbk)编码就为494F,即我们得出的结果,而上对应的Unicode编码为4E0A,我们可以将gbk-->decode-->Unicode。

    047-Python2与3字符编码的区别-Unicode上.png?x-oss-process=style/watermark

    # 六、Python2中代码

    # 七、coding:gbk

    x = '上'.decode('gbk')
    y = '下'.decode('gbk')
    print([x, y])  # [u'u4e0a', u'u4e0b']

    2 Unicode 类型

    当Python解释器执行到产生字符串的代码时(例如s=u'林'),会申请新的内存地址,然后将'林'以Unicode的格式存放到新的内存空间中,所以s只能encode,不能decode。

    # 八、Python2中代码

    # 九、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'>)

    对于print需要特别说明的是:当程序执行时,比如x='上' # gbk下,字符串存放为xc9xcf

    print(x)这一步是将x指向的那块新的内存空间(非代码所在的内存空间)中的内存,打印到终端,按理说应该是存的什么就打印什么,但打印xc9xcf,对一些不熟知Python编码的程序员,立马就懵逼了,所以龟叔自作主张,在print(x)时,使用终端的编码格式,将内存中的xc9xcf转成字符显示,此时就需要终端编码必须为gbk,否则无法正常显示原内容:上。

    047-Python2与3字符编码的区别上1.png?x-oss-process=style/watermark

    047-Python2与3字符编码的区别-上2.png?x-oss-process=style/watermark

    对于Unicode格式的数据来说,无论怎么打印,都不会乱码

    047-Python2与3字符编码的区别-上3.png?x-oss-process=style/watermark

    047-Python2与3字符编码的区别-上4.png?x-oss-process=style/watermark

    Unicode这么好,不会乱码,那Python2为何还那么别扭,搞一个str出来呢?Python诞生之时,Unicode并未像今天这样普及,很明显,好的东西你能看得见,龟叔早就看见了,龟叔在Python3中将str直接存成Unicode,我们定义一个str,无需是否加u前缀,就是一个Unicode,屌不屌?

    3 Python3

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

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

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

    很重要的一点是:看到Python3中x.encode('gbk') 的结果xc9xcf正是Python2中的str类型的值,而在Python3是bytes类型,在Python2中则是str类型。

    总而言之

    在Python2中如果指定了字符编码,那么内存存取就会按照指定的字符编码去入内存。解释或去执行时就要按照指定了的字符编码去解释,否则就会乱码。 否则可以在定义变量前面加上u,这样变量就会以unicode编码存入内存。

    如:

    #coding:gbk

    name = "爸爸"

    但在Python3中就不会有这样的问题,因为无论你指定了什么字符编码,在内存存取时都会使用Unicode编码去入内存,Unicode编码可以和任意的字符编码相互转换,并在读取时按照所需的编码区读取,这样就很好解决了字符编码的问题

    三、 基本的文件操作

    虽然视频、音频和图片在硬盘中也是用二进制存储的,但是上一章节讲的字符编码只和文本文件有关,因为‘utf-8’格式的编码并不使用视频,视频有其本身的编码格式,如MP4、avi、mkv等。

    3、1 什么是文件?

    就是只要我们想要操作文件就是对操作系统发起请求,然后由操作系统将用户或应用程序对文件的读写操作转换成集体的硬盘指令(比如控制盘片转动,控制机械手臂移动,以此来读取数据)。

    3、2 为什么要有文件?

    内存无法永久保存数据,但凡我们想要永久保存数据都需要把文件保存到硬盘中,而操作文件就可以实现对硬件的操作。

    3、3 如何用文件?

    现在我们有一个需求需要把用户输入的账号密码存储到硬盘中,我们使用Python该如何操作呢?

    name = 'nick'
    pwd = '123'

    3.1 从硬盘中读取数据

    open(r'/Users/mac/desktop/jupyter/pythonCourseware/32.txt')

    如果给列表增加值,我们需要给列表赋值后才能给对应的列表增加值。文件也是如此。

    lis = [1,2,3]
    lis.append(4)
    lis.append(5)
    # 打开文件
    f = open(r'/Users/mac/desktop/jupyter/pythonCourseware/32.txt')
    print(f)
    <_io.TextIOWrapper name='/Users/mac/desktop/jupyter/pythonCourseware/32.txt' mode='r' encoding='UTF-8'>

    打开文件之后,文件不仅占用了内存,他还对应了操作系统打开的以文件,相当于使用文本编辑器打开了一个文件。并且我们说了我们操控文件只是为了读和写,因此打开文件并不是目的,读和写才是目的,接下来我们尝试如何读写文件。

    # read模式打开文件
    f = open(r'/Users/mac/desktop/jupyter/pythonCourseware/32.txt', mode='r')
    # 读取文件内容,向操作系统发起读请求,会被操作系统转成具体的硬盘操作,将内容由硬盘读入内存
    data = f.read()
    print(data)
    # 由于Python的垃圾回收机制只回收引用计数为0的变量,但是打开文件还占用操作系统的资源,所以我们需要回收操作系统的资源资源
    # del f 只是回收变量f
    f.close()
    name = 'nick'
    pwd = '123'

    3.2 写入数据

    name = 'nick'
    pwd = '123'

    3、4 总结

    1. 打开文件

    2. 读写

    3. 关闭

    四、绝对路径和相对路径

    4、1 绝对路径

    • Windows系统绝对路径从盘符(C:、D:)开始写一个完整的路径。

    • macos系统从根目录(/Users)开始写一个完整的路径。

    4、2 相对路径

    相对于当前执行文件所在的文件夹开始找。

    五、文件的三种打开方式

    文件操作的基础模式有三种(默认的操作模式为r模式):

    • r模式为read

    • w模式为write

    • a模式为append

    文件读写内容的格式有两种(默认的读写内容的模式为b模式):

    • t模式为text

    • b模式为bytes

    需要注意的是:t、b这两种模式均不能单独使用,都需要与r/w/a之一连用。

    5、1 文件打开模式之r模式

    f = open('32.txt', mode='r')  # 报错
    f.write()
    f.close()
    # rt: read by text
    # windows的操作系统默认编码为gbk,因此需要使用utf8编码
    f = open('32.txt', mode='rt', encoding='utf8')
    data = f.read()
    print(data)
    print(f"type(data): {type(data)}")
    f.close()
    ```
    运行结果:
    aaa
    bbb
    ccc
    nick最帅吗
    ```
    type(data): <class 'str'>
    # rb: read by bytes
    f = open('32.txt', mode='rb')
    data = f.read()
    print(data)
    print(f"type(data): {type(data)}")
    f.close()
    b'aaa bbb ccc nickxe6x9cx80xe5xb8x85xe5x90x97'
    type(data): <class 'bytes'>

    f.read()读取文件指针会跑到文件的末端,如果再一次读取,读取的将是空格。

    f = open('32.txt', mode='rt', encoding='utf8')
    data1 = f.read()
    data2 = f.read()
    print(f"data1: {data1}")
    print(f"data2: {data2}")
    f.close()
    ```
    运行结果:
    data1: aaa
    bbb
    ccc
    nick最帅吗
    data2:
    ```

    由于f.read()一次性读取文件的所有内容,如果文件非常大的话,可能会造成内存爆掉,即电脑卡死。因此可以使用f.readline()/f.readlines()读取文件内容。

    # f.readline()/f.readlines()
    f = open('32.txt', mode='rt', encoding='utf8')
    print(f"f.readable(): {f.readable()}")  # 判断文件是否可读
    data1 = f.readline()
    data2 = f.readlines()
    print(f"data1: {data1}")
    print(f"data2: {data2}")
    f.close()
    f.readable(): True
    ```
    运行结果:
    data1: aaa

    data2: ['bbb ', 'ccc ', 'nick最帅吗']
    ```

    5、2 文件打开模式之w模式

    # wt
    f = open('34w.txt', mode='wt', encoding='utf8')
    print(f"f.readable(): {f.readable()}")
    f.write('nick 真帅呀 ')  # ' '是换行符
    f.write('nick,nick, you drop, I drop.')
    f.write('nick 帅的我五体投地')
    f.flush()  # 立刻将文件内容从内存刷到硬盘
    f.close()
    f.readable(): False
    # wb
    f = open('34a.txt', mode='wb')
    f.write('nick 帅的我五体投地'.encode('unicode_escape'))  # 编码成bytes类型
    print(
       f"type('nick 帅的我五体投地'.encode('unicode_escape')): {type('nick 帅的我五体投地'.encode('unicode_escape'))}")
    f.close()
    type('nick 帅的我五体投地'.encode('unicode_escape')): <class 'bytes'>

    5、3 文件打开模式之a模式

    # at
    f = open('34a.txt', mode='at', encoding='utf8')
    print(f"f.readable(): {f.readable()}")
    f.write('nick 真帅呀 ')  # ' '是换行符
    f.write('nick,nick, you drop, I drop.')
    f.write('nick 帅的我五体投地')
    f.close()
    f.readable(): False

    5、4 文件打开读取二进

    try:
       import requests

       response = requests.get(
           'http://www.chenyoude.com/Python从入门到放弃/文件的三种打开模式-mv.jpg?x-oss-process=style/watermark')
       data = response.content

       f = open('mv.jpg?x-oss-process=style/watermark', 'wb')
       f.write(data)
       print('done...')
       f.close()
    except Exception as e:
       print(e, '报错了,那就算了吧,以后爬虫处会详细介绍')
    done...
    f = open('34w.txt', 'wb')
    f.write('nick 好帅啊'.encode('utf8'))
    f.close()

    六、with管理文件操作上下文

    之前我们使用open()方法操作文件,但是open打开文件后我们还需要手动释放文件对操作系统的占用。但是其实我们可以更方便的打开文件,即Python提供的上下文管理工具——with open()。

    with open('32.txt', 'rt', encoding='utf8') as f:
       print(f.read())
    sdf

    with open()方法不仅提供自动释放操作系统占用的方法,并且with open可以使用逗号分隔,一次性打开多个文件,实现文件的快速拷贝。

    with open('32.txt', 'rb') as fr, 
           open('35r.txt', 'wb') as fw:
       f.write(f.read())

    七、文件的高级应用

    • r+t: 可读、可写

    • w+t: 可写、可读

    • a+t: 可追加、可读

    # wt
    with open('36w.txt', 'wt', encoding='utf-8') as fw:
       print(fw.readable())
       print(fw.writable())
    False
    True
    # w+t
    with open('36w.txt', 'w+t', encoding='utf-8') as fw:
       print(fw.readable())
       print(fw.writable())
    True
    True
    # r+t
    with open('36w.txt', 'r+t', encoding='utf-8') as fr:
       print(fr.readable())
       print(fr.writable())
    True
    True

    文件内指针移动

    with open('36r.txt', 'r+t', encoding='utf-8') as fr:
       fr.readline()
       fr.write('nick 真衰呀')  # 写在文件的最后一行

    硬盘上从来没有修改一说,硬盘上只有覆盖,即新内容覆盖新内容。

    1.seek(offset,whence): offset代表文件指针的偏移量,偏移量的单位是字节个数

    # seek()
    with open('36r.txt', 'rb') as fr:
       print(f"fr.seek(4, 0): {fr.seek(4, 0)}")  # 0相当于文件头开始;1相当于当前文件所在位置;2相当于文件末尾
       # fr.seek(0,2) # 切换到文件末尾
    fr.seek(4, 0): 3

    2.tell(): 每次统计都是从文件开头到当前指针所在位置

    # tell()
    with open('36r.txt', 'rb') as fr:
       fr.seek(4, 0)
       print(f"fr.tell(): {fr.tell()}")
    fr.tell(): 4

    3.read(n): 只有在模式下的read(n),n代表的是字符个数,除此之外,其他但凡涉及文件指针的都是字节个数

    # read()
    with open('36r.txt', 'rt', encoding='utf-8') as fr:
       print(f"fr.read(3): {fr.read(3)}")
    fr.read(3): sdf

    4.truncate(n): truncate(n)是截断文件,所以文件的打开方式必须可写,但是不能用w或w+等方式打开,因为那样直接清空文件了,所以truncate()要在r+或a或a+等模式下测试效果。它的参照物永远是文件头。并且truncate()不加参数,相当于清空文件。

    # truncate()
    with open('36r.txt', 'ab') as fr:
       fr.truncate(2) # 截断2个字节后的所有字符,如果3个字节一个字符,只能截断2/3个字符,还会遗留1/3个字符,会造成乱码

    八、文件修改的两种方式

    文件的数据是存放于硬盘上的,因而只存在覆盖、不存在修改这么一说,我们平时看到的修改文件,都是模拟出来的效果,具体的说有两种实现方式。

    8、1 方式一

    import os

    with open('37r.txt') as fr,
           open('37r_swap.txt', 'w') as fw:
       data = fr.read()  # 全部读入内存,如果文件很大,会很卡
       data = data.replace('tank', 'tankSB')  # 在内存中完成修改

       fw.write(data)  # 新文件一次性写入原文件内容

    # 删除原文件
    os.remove('37r.txt')
    # 重命名新文件名为原文件名
    os.rename('37r_swap.txt', '37r.txt')
    print('done...')
    done...

    8、2 方式二

    import os

    with open('37r.txt') as fr,
           open('37r_swap.txt', 'w') as fw:
       # 循环读取文件内容,逐行修改
       for line in fr:
           line = line.replace('jason', 'jasonSB')
           # 新文件写入原文件修改后内容
           fw.write(line)

    os.remove('37r.txt')
    os.rename('37r_swap.txt', '37r.txt')
    print('done...')
    done...

    总而言之,修改文件内容的思路为:以读的方式打开原文件,以写的方式打开一个新的文件,把原文件的内容进行修改,然后写入新文件,之后利用os模块的方法,把原文件删除,重命名新文件为原文件名,达到以假乱真的目的。

     

     

     

     

  • 相关阅读:
    Centos 7 下安装LDAP 双主同步
    Apache Ranger && HDFS
    Java 学习(六)
    Java学习(五)
    Java学习(四)
    Java学习(三)
    Java学习(二)
    Java学习(一)
    css笔记
    磁盘性能测试方法
  • 原文地址:https://www.cnblogs.com/hanyi12/p/11545288.html
Copyright © 2011-2022 走看看