Top

文件操作

一、初识文件操作

  使用python来读写文件是非常简单的操作,我们使用open( )函数来打开一个文件,获取到文件句柄,然后通过文件句柄就可以进行各种各样的操作了,根据打开方式的不同能够执行的操作也会有相应的差异。

       打开文件的方式有:r,w,a,r+,w+,a+,rb,wb,ab,r+b,w+b,a+b默认使用的是r(只读)模式

二、只读操作(r,rb)

    f = open("你好.txt",mode="r",encoding="utf-8")
    content = f.read()
    print(content)
    f.close()

  需要注意encoding表示编码集,根据文件的实际保存编码进行获取,对于我们而言,更多的是utf-8。

  rb读取出来的数据是bytes类型,在rb模式下,不能选择encoding字符集,具体示例如下:

    f = open("你好.txt",mode="rb")
    content = f.read()
    print(content)
    f.close()
    结果为:
    b'hello world\r\n\xe7\xaa\x97\xe5\x89\x8d\xe6\x98\x8e\xe6\x9c\x88\xe5\x85\x89\r\n\r\n'

  rb的作用:在读取非文本文件的时候,比如读取MP3,图像,视频等信息的时候就需要用到rb,因为这种数据是没办法直接显示出来的,在后面我们文件上传下载的时候还会用到,还有我们看的直播,实际上都是这种数据。

相对路径和绝对路径:

       1,绝对路径:从磁盘目录开始一直到文件名 或者 从互联网上寻找一个路径

       2,相对路径:相对于当前程序所在的文件夹   ../上一层文件夹

注意:更推荐大家使用相对路径,因为在我们把程序拷贝给别人使用的时候,直接把项目拷贝走就能运行,但是如果用绝对路径,那还需要拷贝外部的文件。

读取文件的方法:read( ),read(n),readline( ),readlines( ),还有for循环读取。

1,read( )

  将文件中的内容全部读取出来,弊端:占内存,如果文件过大,容易导致内存崩溃。

    f = open("你好.txt",mode="r",encoding="utf-8")
    content = f.read()
    print(content)
    f.close()
2,read(n)

  读取n个字符,需要注意的是:如果再次读取,那么会在当前位置继续去读而不是从头读,如果使用的是rb模式,则读取出来的是n个字节。具体示例如下:

    f = open("你好.txt",mode="r",encoding="utf-8")
    content = f.read(3)   #读取出来3个字符
    print(content)  
    f.close()

    f = open("你好.txt",mode="rb")
    content = f.read(3)   # 读取出来3个字节
    print(content)
    f.close()

    f = open("你好.txt",mode="r",encoding='utf-8')
    content1 = f.read(3)   # 读取出来3个字符
    content2 = f.read(3)   # 接着刚才的位置再读取3个字符
    print(content1)
    print(content2)
    f.close()
3,readline( )

  一次读取一行数据,注意:readline( )结尾,每次读取出来的数据都会有一个\n,所以,需要我们使用strip( )方法来去掉\n或者空格。具体如下示例:

    f = open("你好.txt",mode="r",encoding='utf-8')
    content1 = f.readline()
    content2 = f.readline()
    content3 = f.readline()
    print(content1)
    print(content2)
    print(content3)
    f.close()
4,readlines( )

  将每一行形成一个元素,放到一个列表中,然后将所有的内容都读取出来,所以,同理,也容易出现内存崩溃的问题,不推荐使用。具体如下示例:

    f = open("你好.txt",mode="r",encoding='utf-8')
    lst = f.readlines()
    print(lst)
    for line in lst:
        print(line.strip())
    f.close()
5,循环读取

  这种方式是最好的,每次读取一行内容,不会产生内存溢出的问题。具体如下示例:

    f = open("你好.txt",mode="r",encoding="utf-8")
    for line in f:
        print(line.strip())
  f.close()

注意:读取完的文件句柄一定要关闭,即f.close()

三、写模式(w,wb)

读的时候,如果所读取的文件不存在,则会报错;

写的时候注意,如果没有文件,则会创建文件,如果文件存在,则将文件中原来的内容全部删除,再写入新内容;

    f = open("小娃娃",mode="w",encoding="utf-8")
    f.write("金毛狮王") # 文件中原内容全部删除并写入金毛狮王
    f.flush()   # 刷新,要养成好习惯
    f.close()

尝试读一读:

    f = open("你好",mode="w",encoding="utf-8")
    f.write("hello world")
    f.read()  # 报错:not readable ,因为模式是w. 不可以执行读操作
    f.flush()
    f.close()

wb模式下,可以不指定打开文件的编码,但是在写文件的时候必须将字符串转化成utf-8的bytes数据。如下:

    f = open("你好.txt",mode="wb")
    f.write("你是谁?".encode("utf-8"))
    f.flush()
    f.close()

四,追加(a,ab)

在追加模式下,我们写入的内容会追加在文件的结尾(默认不换行,换行需要手动控制,即\n),具体如下示例:

    f = open("你好.txt",mode="a",encoding="utf-8")
    f.write("你的最爱")
    f.flush()
    f.close()

五,读写模式(r+,r+b)

对于读写模式,必须是先读,因为默认光标是在开头的,准备读取的,当读完了之后再进行写入,我们以后使用频率最高的模式就是r+。

正确的操作是:

    f = open("你好.txt",mode="r+",encoding="utf-8")
    content = f.read()
    f.write("你的最爱?")
    print(content)
    f.flush()
    f.close()
    # 结果:正常的读取之后,写在结尾

错误的操作:

    f = open("你好.txt",mode="r+",encoding="utf-8")
    f.write("你的最爱")
    content = f.read()
    print(content)
    f.flush()
    f.close()
    # 结果:将开头的内容(4个字符)改写成了“我的最爱”,然后读取的是后面的内容

综上,所以记住:在r+模式下,必须是先读取,然后再写入。

深坑请注意:在r+模式下,如果读取了内容,不论读取内容多少,光标显示的是多少,再写入或者操作文件的时候都是在结尾进行的操作。

六,写读(w+,w+b)

先将所有的内容清空,然后写入,最后读取,但是读取的内容是空的,不常用。具体操作如下示例:

    f = open("你好.txt",mode="w+",encoding="utf-8")
    f.write("哈哈")
    content = f.read()
    print(content)
    f.flush()
    f.close()

  有人会说,先读不就好了么?错,在w+模式下,一开始读取不到数据,然后写的时候再将原来的内容清空,所以,很少用。

七,追加读(a+)

a+模式下,不论先读还是后读,都是读取不到数据的。

    f = open("你好.txt",mode="a+",encoding="utf-8")
    f.write("麻花藤")
    content = f.read()
    print(content)
    f.flush()
    f.close()

还有一些其他的带b的操作,在此就不一一举例了,就是把字符换成字节,仅此而已。

八,其他相关操作:seek(n),tell( ),truncate( )

8.1 seek(n)

  光标移动到n位置,注意:移动的单位是byte,所以如果是utf-8的中文部分要是3的倍数。

       通常我们使用seek都是移动到开头或者结尾。

       移动到开头:seek(0)

       移动到结尾:seek(0,2)

  seek的第二个参数表示的是从哪个位置进行偏移,默认是0,表示开头,1表示当前位置,2表示结尾。

    f = open("你好.txt",mode="r+",encoding="utf-8")
    f.seek(0)  # 光标移动到开头
    content = f.read()  # 读取内容,此时光标移动到结尾
    print(content)
    f.seek(0)  # 再次将光标移动到开头
    f.seek(0,2)  #将光标移动到结尾
    content2 = f.read()   # 读取内容,什么都读不到
    print(content2)

    f.seek(0)  # 光标移动到开头
    f.write("张国荣")  # 写入信息,此时光标在9,即中文3 bytes * 3个 = 9

    f.flush()
    f.close()
8.2 tell( )

  使用tell( )可以帮我们获取到当前光标在什么位置。

    f = open("你好.txt",mode="r+",encoding="utf-8")
    f.seek(0)  # 光标移动到开头
    content = f.read()  # 读取内容,此时光标移动到结尾
    print(content)
    f.seek(0)  # 再次将光标移动到开头
    f.seek(0,2)  #将光标移动到结尾
    content2 = f.read()   # 读取内容,什么都读不到
    print(content2)

    f.seek(0)  # 光标移动到开头
    f.write("张国荣")  # 写入信息,此时光标在9,即中文3 bytes * 3个 = 9

    print(f.tell())  # 结果为:9   即光标位置是 9

    f.flush()
    f.close()
8.3 truncate( )

  截断文件

    f = open("你好.txt",mode="w",encoding="utf-8")
    f.write("哈哈哈")  # 写入3个字符
    f.seek(3)  # 光标移动3个字节,也就是两个字中间
    f.truncate()  # 删掉光标后面的所有内容
    f.close()
    
    f = open("你好.txt",mode="r+",encoding="utf-8")
    content = f.read(3)  # 读取3个字符
    f.seek(6)  # 光标从开始向右移动2个字符
    print(f.tell())
    f.truncate()  # 光标后面的所有内容全部都删掉(注意:若不移动光标的话默认先读再truncate的话是不会删除任何内容的,原因参见r+的坑)
    print(content)  
    f.flush()
    f.close()

  深坑请注意:在r+模式下,如果读取了内容,不论读取内容多少,光标显示的是多少,再写入或者操作文件的时候都是在结尾进行的操作。所以注意,r+模式下,不移动光标的话,截断文件操作删不掉内容。

  所以如果想做截断操作,记住了,如果truncate不写参数n的情况下,要先挪动光标,挪动到你想要截断的位置,然后再进行截断;关于truncate(n), 如果给出了n,则可以不用f.seek手动移动光标,truncate(n)表示光标从开头向右移动n个字节开始进行截断,后面内容全部删除;如果不给n,则表示从光标当前位置截断, 后面的内容将会被删除,即要f.seek手动移动光标,否则删不掉内容。

九,修改文件以及另一种打开文件的方式

       文件修改:只能将文件中的内容读取到内存中,将信息修改完毕,然后将原文件删除,将新的文件的名字改成原文件的名字。

    # 文件修改
    import os
    with open("你好.txt",mode="r",encoding="utf-8") as f1,\
        open("你好_new.txt",mode="w",encoding="utf-8") as f2:
        content = f1.read()
        new_content = content.replace("冰糖葫芦","大白梨")
        f2.write(new_content)
    os.remove("你好.txt")  # 删除原文件
    os.rename("你好_new.txt","你好.txt")   # 重命名新文件

弊端:一次将所有内容进行读取,内存溢出。解决方案:一行一行的读取和写入。具体操作如下示例:

    import os
    with open("你好.txt",mode="r",encoding="utf-8") as f1,\
        open("你好_new.txt",mode="w",encoding="utf-8") as f2:
        for line in f1:
            new_line = line.replace("冰糖葫芦","大白梨")
            f2.write(new_line)
    os.remove("你好.txt")  # 删除原文件
    os.rename("你好_new.txt","你好.txt")   # 重命名新文件

 

posted @ 2018-08-06 17:53  勇敢的巨蟹座  阅读(203)  评论(0编辑  收藏  举报