Python基础(四)-文件操作

一、文件操作的流程

1)打开文件,得到文件句柄并赋值给一个变量

2)通过句柄对文件进行操作

3)关闭文件

#方式一:
#打开文件,得到文件句柄并赋值给一个变量
f=open('a.txt','r',encoding='utf-8') #默认打开模式就为r

#2通过句柄对文件进行操作
data=f.read()

#3关闭文件
f.close()    #回收操作系统打开的文件
#------------------------------------------------------
#方式二:
with open('a.txt','r') as read_f,open('b.txt','w') as write_f:
    data=read_f.read()
    write_f.write(data)

注意:f=open(..)是由操作系统打开文件,由操作系统默认的编码决定(windows:gbk,linux:utf-8),若要保证不乱码,文件以什么方式存的,就要以什么方式打开

二、文件打开的模式

模式 描述
r 只读模式,文件的指针在文件开头(默认模式,文件必须存在,不存在则抛出异常)
rb 以二进制格式打开一个文件,指针默认在文件开头,一般用于图片或者视频等非文本
r+ 读写模式,指针在文件开头
w 只写,会先清空文件内容在进行写入(不可读,不存在则创建,存在则清空内容)
wb 以二进制打开文件进行写入,会先清空文件内容在进行写入,一般用于图片等非文本
w+写读,会清空文件内容在进行写入和读取
a 追加写入,文件的指针在文件的结尾(不可读,不存在则创建,存在则只追加内容)
ab 以二进制文件打开文件进行追加,文件指针会在结尾

注意:

1)以b方式打开时,读取到的内容是字节类型,写入时也需要提供字节类型,不能指定编码

2)文件的相对路径与绝对路径

  • 绝对路径: 从磁盘根目录开始一直到文件名
  • 相对路径: 以当前目录为基准,在当前目录下相对路径就是当前文件名

2.1、只读模式(r,rb)

with open("read_file.txt",mode="r",encoding="utf-8") as f:
    print(f.read())

#你好
#abcdefghi

encoding:字符集,根据文件的实际保存编码进行获取数据,常用的就是 utf-8,如果不指定encoding会出现乱码,因为open()会议操作系统的默认编码格式来获取数据(gbk),而文件实际保存的格式是utf-8

with open("read_file.txt",mode="rb") as f:
    print(f.read())    

#b'\xe4\xbd\xa0\xe5\xa5\xbd\r\nabcdefghi'

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

rb 作用: 在读取非文本文件的时候,比如读取音频,图像,视频等信息可以用到

文件读取的方式

f.read()       #读取所有内容,光标移动到文件末尾 , 占用内存大,如果文件过大,容易导致内存崩溃
f.readline()   #读取一行内容,每次读取出来的数据都会有一个\n,可以使用.strip()或print(f.readline(),end=””)去除
f.readlines()  #读取每一行内容,存放于列表中

with open("read_file.txt",mode="r",encoding="utf-8") as f:
    print(f.readline())
    print(f.readline())

#输出有空行
你好

abcdefghi
-----------------------------------------------------------
with open("read_file.txt",mode="r",encoding="utf-8") as f:
    print(f.readline().strip())
    print(f.readline().strip())

#输出去除了空行
你好
abcdefghi
---------------------------------------------------------

#循环读取,每次读取一行内容,不会产生内存溢出的问题
with open("read_file.txt",mode="r",encoding="utf-8") as f:
    for line in f:
        print(line.strip())


你好
abcdefghi

2.2、只写模式(w,wb)

写模式如果文件不存在会自动创建文件,如果文件存在会情况原有内容,在写入新内容

with open("read_file.txt",mode="w",encoding="utf-8") as f:
    f.write("只写模式")
    f.flush()

#文件内容只剩下只写模式

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

with open("read_file.txt",mode="wb") as f:
    f.write("wb模式".encode("utf-8"))
    f.flush()

#文件内容:wb模式

2.3、追加模式(a,ab)

在追加模式下,写入的内容会追加在文件的结尾

with open("read_file.txt",mode="a",encoding="utf-8") as f:
    f.write("abc")
    f.write("\nabc")   #使用\n换行
    f.flush()

wb模式abc
abc

ab 模式的写法和 wb一样

with open("read_file.txt",mode="ab") as f:
    f.write("ab模式".encode("utf-8"))
    f.flush()

wb模式abc
abcab模式

2.4、读写模式(r+)

对于读写模式,必须是先读. 因为默认的光标是在开头,当读完了之后在进行写入
注意:在 r+ 模式下,如果读取了文件内容,无论读取内容多少,光标显示在是多少,再写入文件时都是在文件结尾写入

with open("read_file.txt",mode="r+",encoding="utf-8") as f:
    print(f.read())
    f.write("\nr+模式")
    f.flush()

#输出
wb模式abc
abcab模式

#文件内容
wb模式abc
abcab模式
r+模式

2.5、写读模式(w+)

先将文件所有的内容清空,然后写入,最后读取.但读取的内容为空

with open("read_file.txt",mode="w+",encoding="utf-8") as f:
    f.write("w+模式")
    print(f.read())
    f.flush()

#输出为空,因为写入之后光标在最后,后面没有内容读取
#文件内容:w+模式

2.6、追加读模式(a+)

a+ 模式下,不论是先读还是后读,都是读取不到数据的,因为光标都在最后

with open("read_file.txt", mode="a+", encoding="utf-8") as f:
    f.write("a+模式")
    print(f.read())
    f.flush()

#没有输出,因为光标在文件结尾
文件内容:w+模式a+模式

三、文件其他操作

3.1、光标移动seek()

格式:seek(偏移量,偏移位置)

seek(0)  ==>移动光标到开头

seek(0,2)   ==>移动光标到结尾

第一个参数:代表移动的偏移量

第二个参数:从哪个位置进行偏移,默认是0

  • 0:表示开头
  • 1:表示当前位置
  • 2:表示结尾

注意:seek(n) 光标移动到 n 位置,移动的单位是 byte,如果是 UTF-8 的中文部分要是3的倍速

with open("read_file.txt",mode="r+",encoding="utf-8") as f:
    f.seek(0)        #移动光标到开头
    print(f.read())  #读取文件内容,此时光标在结尾
    f.seek(0)        #移动光标到开头
    f.seek(0,2)      #移动光标到结尾
    print(f.read())  #此时读取不到内容
    f.seek(0)        #移动光标到开头
    f.write("abc")   #覆盖开头的字符
    print(f.tell())  #查看光标位置
    f.flush()        #刷新文件到磁盘

#文件内容:12345678  ==>  abc45678

3.2、光标位置tell()

with open("read_file.txt",mode="r+",encoding="utf-8") as f:
    print(f.tell())
    f.seek(3)   #光标移动3个字节
    print(f.tell())
    f.seek(0,2)  #光标移动到结尾
    print(f.tell())  

3.3、文件截断truncate()

截取文件是从开头开始,到你光标位置
如果 truncate(n) 内 n 给出了位置,则就是从开头开始到 n 位置的截取

with open("read_file.txt",mode="w+",encoding="utf-8") as f:
    f.write("abcdef")
    f.seek(3)
    f.truncate()  #截取开头到当前位置的内容
    f.seek(0)
    print(f.read())

#abc

四、文件操作方法总结

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

注意

1)read(3)

  • 文件打开方式为文本模式时,代表读取3个字符
  • 文件打开方式为b模式时,代表读取3个字节

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

五、文件操作需求

5.1、大文件读取最后一行(日志文件)

#日志文件
2016/12/25 a
2016/12/26 b
2016/12/27 c
2016/12/28 a
2016/12/29 d
2016/12/30 s


f=open('日志文件','rb')
for i in f:
    offs=-10
    while True:
        f.seek(offs,2)
        data=f.readlines()  #readlines获取的是一个列表
        if len(data) > 1:   #列表的长度说明不只获取了最后一行
            print('文件的最后一行是%s' %(data[-1].decode('utf-8')))
            break
        offs*=2

#文件的最后一行是2016/12/30 s

5.2、文件的修改

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

方式一:将硬盘存放的该文件的内容全部加载到内存,在内存中是可以修改的,修改完毕后,再由内存覆盖到硬盘(word,vim,nodpad++等编辑器)

import os
with open("a.txt",mode="r",encoding="utf-8") as read_f,\
        open(".a.txt.swap","w") as write_f:
    data = read_f.read()   #全部读入内存,如果文件很大,会很卡
    data = data.replace("aaa","bbb")  #在内存中修改
    write_f.write(data)   #一次性写入新文件

os.remove("a.txt")
os.rename(".a.txt.swap","a.txt")

方式二:将硬盘存放的该文件的内容一行一行地读入内存,修改完毕就写入新文件,最后用新文件覆盖源文件

import os
with open("a.txt",mode="r",encoding="utf-8") as read_f,\
        open(".a.txt.swap","w") as write_f:
    for line in read_f:
        line = line.replace("aaa","bbb")
        write_f.write(line)

os.remove("a.txt")
os.rename(".a.txt.swap","a.txt")
posted @ 2019-09-05 14:31  运维人在路上  阅读(290)  评论(0编辑  收藏  举报