py_13文件操作和方法

image.png

总结文件对象方法:

文件对象方法
f.read() 有参数表从开头读多少个字节,没有读取所有内容。读小文件推荐
f.readline() 读取一行内容,光标移动到第二行首部.读大文件推荐,或者 for line in 遍历
f.readlines() 读取每一行内容,存放于列表中.返回值是一个列表包含'\n'.读小文推荐
f.write() f.write('1111\n222\n') #针对文本模式的写,需要自己写换行符。内容必须是 字符串
f.write() f.write('1111\n222\n'.encode('utf-8')) #针对b模式的写,需要自己写换行符。返回是int 字符数
f.writelines() f.writelines(['333\n','444\n']) #文本模式。列表元素必须是 字符串
f.writelines() f.writelines([bytes('333\n',encoding='utf-8'),'444\n'.encode('utf-8')]) #b模式
f.seek(x,y) seek(x, 0):从开始位置向右 x 个字符
f.seek(x,y) seek(x, 1):当前位置往右移动 x 个字符
f.seek(x,y) seek(-x, 2):文件的结尾向左移动 x 个字符
f.tell() 返回文件的当前位置
f.truncate() 清空文件,配合f.seek(0) 使用,调整指针位置。
f.closed 文件是否关闭
f.flush() 立刻将文件内容从内存刷到硬盘
f.readable() 文件是否可读
f.writable() 文件是否可写
f.name 文件名字

文件操作

一、文件
  应用程序向操作系统发出指令,实际是操作硬盘。可以将数据永久保存到硬盘中去
二、如何使用文件:
    1.打开文件 2.读写文件 3.关闭文件。
文件操作的基本步骤:1.打开文件 2.读写文件 3.关闭文件。
四、chardet识别文件编码
    - chardet.detect(data)  # data为 文件内容,返回一个字典。
    - 字典为:{'encoding': 编码, 'confidence': 可信度, 'language': 语言}
五、with上下文管理
    打开一个:with open('a.txt','w') as f:
    打开多个:with open('a.txt','r') as read_f,open('b.txt','w') as write_f:
六、文件的操作模式
    1.控制文件读写操作的模式
        r(默认的):只读,指针在开头
        w:只写  ,指针在开头
        a:只追加写,指针在末尾
        r 、w、a一般运用场景:
            1. `r 一般读取文件,可以运用于用户是否注册,登录是否成功`
            2. `w 一般用于新建新文件,比如 文件拷贝功能,打开老文件,重新写入新文件`
            3. `a 一般用于打开老的文件。如果注册功能,记录日志。`
    2.控制文件读写内容的模式
    
        大前提: tb模式均不能单独使用,必须与r/w/a之一结合使用
        t(默认的):文本模式
            1. 读写文件都是以字符串为单位的
            2. 只能针对文本文件
            3. 必须指定encoding参数
        b:二进制模式:
            1.读写文件都是以bytes/二进制为单位的,任何文件都可以用b模式读取或写入
            2. 可以针对所有文件
            3. 一定不能指定encoding参数
七、操作文件的方法:
    # 读操作
    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模式
    
    bytes===>二进制
        1. 字符串编码encode之后的结果
            1.1 "字符串".encode("utf-8")
            1.2 bytes("字符串",encoding="utf-8")
        1. b"必须是纯英文字符"
        2. b模式下打开文件,读取的内容
        用处:可以存到硬盘里面去
        
    循环读取文件的两种方式:
        1. for line in f:
            pass
        2. while True:
                data = f.read(1024)
                #data=f.readline()
                if len(data) == 0:
                    break
八、主动控制文件内指针移动seek():
    # 0: 默认的模式,该模式代表指针移动的字节数是以文件开头为参照的
    # 1: 该模式代表指针移动的字节数是以当前所在的位置为参照的
    # 2: 该模式代表指针移动的字节数是以文件末尾的位置为参照的
# 强调:其中0模式可以在t或者b模式使用,而1跟2模式只能在b模式下用

九、修改文件的两种方式:       
    1.将文件内容发一次性全部读入内存,然后在内存中修改完毕后再覆盖写回原文件
    2.以读的方式打开原文件,以写的方式打开一个临时文件,一行行读取原文件内容,修改完后写入临时文件...,        删掉原文件,将临时文件重命名原文件名
    3.r+读出内容修改---清空(truncate)--写入  # 这条制作参考。同时又读又写,工作中很少这么去干
    
    
    
    
    
    

先看个案例:

filename = 'data.log'
# 打开文件(a+ 追加读写模式)
# 用 with 关键字的方式打开文件,会自动关闭文件资源
with open(filename, 'w+', encoding='utf-8') as file:
    print('文件名称: {}'.format(file.name))            #  文件名称: data.log
    print('文件编码: {}'.format(file.encoding))        # 文件编码: utf-8
    print('文件打开模式: {}'.format(file.mode))       # 文件打开模式: w+
    print('文件是否可读: {}'.format(file.readable()))     # True
    print('文件是否可写: {}'.format(file.writable()))     # True
    print('此时文件指针位置为: {}'.format(file.tell()))   # 0   r r+ w w+ 打开文件指针都是在开头
    # 写入内容
    # f.write()返回是int字符数
    num = file.write("第一行内容\n")
    print('写入文件 {} 个字符'.format(num))   # 写入文件 6 个字符
    # 文件指针在文件尾部,故无内容
    print(file.readline(), file.tell())     # 17
    # 改变文件指针到文件头部
    file.seek(0)
    # 改变文件指针后,读取到第一行内容
    print(file.readline(), file.tell())  # 第一行内容   17
    # seek(0)修改文件的指针后,却不会影响到写入的位置
    file.write('第二次写入的内容\n')
    # 文件指针又回到了文件尾
    print(file.readline(), file.tell())    # 43
    # file.read() 从当前文件指针位置读取指定长度的字符
    file.seek(0)
    # 读取指定字符数 f.read(int)
    print(file.read(9))
    # 按行分割文件,返回字符串列表
    file.seek(0)
    # readlines() 返回的是一个列表,包括\n
    print(file.readlines())
    # 迭代文件对象,一行一个元素   #   ['第一行内容\n', '第二次写入的内容\n']
    file.seek(0)
    # 文件对象可以for循环遍历,遍历的是每行的数据
    for line in file:
        print(line, end='')
# 关闭文件资源
if not file.closed:   # with上下文处理器,自动关闭
    file.close()
结果:
文件名称: data.log
文件编码: utf-8
文件打开模式: w+
文件是否可读: True
文件是否可写: True
此时文件指针位置为: 0
写入文件 6 个字符
 17
第一行内容
 17
 43
第一行内容
第二次
['第一行内容\n', '第二次写入的内容\n']
第一行内容
第二次写入的内容

一、什么是文件

文件就是操作系统提供给应用程序来操作硬盘虚拟概念,用户或应用程序通过操作文件,可以将自己的数据永久保存下来

为什么要用文件:

用户/应用程序可以通过文件将数据永久保存到硬盘中去。

用户/应用程序直接操作的是文件,对文件进行的所有操作,都是在向操作系统发送系统调用,然后再操作将其转换成具体的硬盘操作

image.png

二、如何用文件:open()

  • 控制文件读写内容的模式:t和b

    • 强调:t和b不能单独使用,必须跟r/w/a连用
    • t文本 (默认的模式)
      • 1.读写都以str (unicode)为单位的
      • 2.文本文件
      • 3.必须指定encoding = 'utf-8'
    • b 二进制/bytes
  • 控制文件读写操作的模式

文件打开模式:

image.png

三、文件操作的基本步骤:

  1. 打开文件 字符串文件路径前面加个r

  2. 读写文件

  3. 关闭文件

    # -*- coding: utf-8 -*-
    """
    ===========================
    # @Time : 2020/7/31 9:56
    # @File  : 基本操作流程.py
    # @Author: adeng
    # @Date  : 2020/7/31
    ============================
    """
    
    # 基本流程
    #    1. 打开文件,得到文件句柄并赋值给一个变量
    #    2.读写文件
    #    3.关闭文件---f.close()
    
    # 1. t文本的流程
    # 打开文件
    # r 只读模式【默认模式,文件必须存在,不存在则抛出异常】
    # 文件打开的原则是“ 以什么编码格式保存的,就以什么编码格式打开 ”
    f = open(r'adeng.txt',mode="r", encoding="utf-8")  # 默认模式是r
    # f = open('adengXXX.txt',mode="r", encoding="utf-8")  # 默认模式是r # 这里注释的代码,文件不存在会报错
    # 读文件
    # f.read() 读取所有内容,光标移动到文件末尾,小文件考虑,大文件消耗cpu过大
    data = f.read()
    print(data)
    
    #  关闭文件
    f.close()
    
    """
    输出:
    我是阿登
    hello word!!
    """
    print("二进制读文件".center(50,'-'))
    # 二进制读文件
    #‘rb’表示以二进制读模式(硬盘存为存的二进制打开就为二进制,并且不再需要指定编码)
    f = open(r'adeng.txt',mode="rb")  # encoding="utf-8" rb不指定编码
    print("文件模式:", f.mode)
    # 读文件
    # f.read() 读取所有内容,光标移动到文件末尾,小文件考虑,大文件消耗cpu过大
    data = f.read()
    # data = f.read().decode("utf-8") # 跟代码24行读取的一致.用了decode
    print(data)
    
    #  关闭文件
    f.close()
    """
    输出:
     b'\xef\xbb\xbf\xe6\x88\x91\xe6\x98\xaf\xe9\x98\xbf\xe7\x99\xbb\r\nhello word!!'
    """
    
    
1、f.close() #回收操作系统打开的文件资源
2、del f #回收应用程序级的变量
# 顺序先1 才能2

指定文件编码

  • rt模式方便了文件的读写,但仅限文本文件。可以参考二进制文件的写需要编码
  • encoding参数没有,会以默认的编码读写,在不同的系统容易报错
# -*- coding: utf-8 -*-
"""
===========================
# @Time : 2020/8/10 10:58
# @File  : 03文件指定编码.py
# @Author: adeng
# @Date  : 2020/8/10
============================
"""

"""
encoding参数不指定编码,带来的影响
linux默认编码:utf-8
苹果系统默认编码:utf-8
win默认编码:utf-8
"""
# 相对路径现在有一个文件 中文01.txt 编码是utf-8

f = open("中文01.txt",mode="rt")
res = f.read() # UnicodeDecodeError: 'gbk' codec can't decode byte 0xaf in position 8: illegal multibyte sequence
"""
上面19,20行两行代码干了什么事?
19行:pyhon解释器(应用程序)赋值给f一个变量,生成了一个文件类型的内存空间。open()函数指应用程序向操作系统windowns发出指定以文本读取的方式
打开文件中文01.txt
20行:操作系统读取硬盘的内容到内存中去,并用gbk去decode解码。
上面20行的代码会报错,因为windowns默认是GBK编码。rt模式必须是unicode,就是str类型。encoding参数没有指定utf-8,而是默认以GBK解码,所以报错。
如果你用的苹果系统就不会报错。为了防止不同系统读取文件发生错误,我们得给encoding指定什么格式去解码。正确的写法如下:
"""
f = open("中文01.txt", mode="rt", encoding="utf-8")
res = f.read()
print(res)  # 我是阿登
# 有了 encoding ="编码" 调用write方法会默认以encoding的编码写入到硬盘。如果没有需要转换编码再写入。所以rt模式方便了文件的读写,但仅限文本文件。可以参考二进制文件的写需要编码。

四、chardet识别文件编码

  • chardet.detect(data) # data为 文件内容,返回一个字典。
  • 字典为:{'encoding': 编码, 'confidence': 可信度, 'language': 语言}
# -*- coding: utf-8 -*-
"""
===========================
# @Time : 2020/8/1 15:59
# @File  : file_detection.py
# @Author: adeng
# @Date  : 2020/8/1
============================
"""
import chardet

'''
pip3 install chardet 第三方包没有就安装
'''

# 在file_detection.py这个目录中创建一个编码01.txt是文档。我们现在不知道他的编码格式。等会读取就用rb模式

def file_encoding(filepath):
    """
    filepath: 文件的路径,非目录
    """
    with open(filepath,"rb") as f1 :
        data = f1.read()
        result = chardet.detect(data) # {'encoding': 编码, 'confidence': 可信度, 'language': 语言}
        print(result)
        encoding = result.get("encoding")
    return encoding

# 之后我们要打开一个文件 就可以直接调用file_mode(filepat) 这个函数返回结果作为open()函数encoding参数值

file_path = r"I:\python20\softwaredate\py_basics\文件操作\文件编码检测\编码01.txt"

with open(file_path,mode="r",encoding=file_encoding(file_path)) as f:
    datas = f.read()
    print(datas)

"""
结果
\xef\xbb\xbf\xe6\x88\x91\xe6\x98\xaf\xe9\x98\xbf\xe7\x99\xbb\r\nhello word!!
史学界认为,解放军成立的事件,是在1927年的“八一”南昌起义打响了武装反抗国民党反动派的第一枪,
宣告我党独立领导革命武装和创建革命军队的开始。所以从1927年到2020年,是建军93周年。建军节的诞生之地1933年7月11日,
中华苏维埃共和国临时中央政府决定将8月1日作为中国工农红军成立纪念日。
从此,每年8月1日就成为中国工农红军和后来中国人民解放军的建军节。当年8月1日,在瑞金叶坪红军广场举行了历史上第一个“八一”纪念活动,
并且当日傍晚在瑞金城南竹马岗举行了红军阅兵式和分列式。从此,8月1日正式成为人民军队的建军节。因此,可以说南昌是军旗升起的地方,
而瑞金是八一建军节诞生的地方。
"""

# chardet.detect(data) 检查文本内容编码类型

五、with上下文管理

# 1、在执行完子代码块后,with 会自动执行f.close()
with open('a.txt','w') as f:
    pass 

# 2、可用用with同时打开多个文件,用逗号分隔开即可
with open('a.txt','r') as read_f,open('b.txt','w') as write_f:  
    data = read_f.read()
    write_f.write(data)

案例:一个文件名是a.txt,现在需要复制a.txt到一个新文件b.txt,用with上下文管理如何操作

import os

# 案例:一个文件名是a.txt,现在需要复制a.txt到一个新文件b.txt,用with上下文管理如何操作
"""
分析要复制一个文件,需要得到这个文件的内容
然后写入到另外一个文件
"""

with open("a.txt",mode="r+",encoding="utf-8") as f1,\
    open("b.txt",mode="w",encoding="utf-8") as f2:
    
    f2.write(f1.read())
    
# os.remove("a.txt")
# os.rename("b.txt", "a.txt")

"""
如果复制文件到另外一个文件,原文件删除,新文件重命名为原文件。 请看注释掉的代码
"""
# 强调:
# 1、硬盘空间是无法修改的,硬盘中数据的更新都是用新内容覆盖旧内容
# 2、内存中的数据是可以修改的

# 另外一种方式:第一个文件一行行的读,第2个文件一行行的写。这样大文件内存消耗会小得多
with open("a.txt",mode="r+",encoding="utf-8") as f1,\
    open("b.txt",mode="w",encoding="utf-8") as f2:
    for line in f1:
        f2.write(line)

# os.remove("a.txt")
# os.rename("b.txt", "a.txt")

结果:

image.png

六、文件的操作模式

1.控制文件读写操作的模式

  • r(默认的):只读,指针在开头

  • w:只写 ,指针在开头

  • a:只追加写,指针在末尾

    r 、w、a一般运用场景:

    1. r 一般读取文件,可以运用于用户是否注册,登录是否成功
    2. w 一般用于新建新文件,比如 文件拷贝功能,打开老文件,重新写入新文件
    3. a 一般用于打开老的文件。如果注册功能,记录日志。

案例一:r 模式的使用

# r只读模式: 在文件不存在时则报错,文件存在文件内指针直接跳到文件开头
with open('adeng01.txt',mode='r',encoding='utf-8') as f:
    res=f.read() # 会将文件的内容由硬盘全部读入内存,赋值给res
    print("第一次读取".center(40,"="))
    print(res)
    print("第2次读取".center(40, "="))
    # f.seek(0,0)
    print(f.tell())
    res1 = f.read()  # 会发现第2次读取是空,是因为read()读取所有内容,指针放在末尾. f.seek(0)调整光标位置,又能打印出来了。
    print(res1)

#db.txt文件的内容:
adeng:123456
向佳:123456
维维:123456
陈勇:123456
徐州:123456
# 实现登录认证的一个小功能,判断用户是否登录成功
inp_name = input("输入你的用户名:").strip()
inp_pwd = input("输入你的密码:").strip()

with open(r"db.txt",mode="rt", encoding="utf-8") as f:
    for line in f :
        user,pwd = line.strip("\n").split(":") # 
        if user ==inp_name and pwd == inp_pwd:
            print("登录成功")
            break  # 登录成功 跳出循环
    else: # 循环结束加else,判定是否真的没登录成功
        print("账号或者用户名输入错误") 

案例二:w 模式的使用

# w只写模式: 在文件不存在时会创建空文档,文件存在会清空文件,文件指针跑到文件开头
# 一个中文相当于=3个字符,1个英文=1个,\n=2个
with open('b.txt',mode='w+',encoding='utf-8') as f:
    f.write('你好\n')
    print(f.tell())
    f.seek(0,0)
    f.readline()
    print(f.tell())
    f.write('我好\n')
    print(f.tell())
    f.write('大家好\n')
    print(f.tell())
    f.write('111\n222\n333\n')
结果:    
9
9
17
28
#强调:
# 1 在文件不关闭的情况下,连续的写入,后写的内容一定跟在前写内容的后面.
# 2 如果重新以w模式打开文件,则会清空文件内容
# W 模式一般用在创作全新的文件,因为如果w模式打开原文件,会先清空再写入。

# 案例 拷贝功能 原来的文件读出来,写入到新文件。
with open("b.txt","r",encoding="utf-8") as f1,open("c.txt","w",encoding="utf-8") as f2:
    for line in  f1:
        f2.write(line)

案例三:a 模式的使用

# a只追加写模式: 在文件不存在时会创建空文档,文件存在会将文件指针直接移动到文件末尾
 with open('c.txt',mode='a',encoding='utf-8') as f:
     f.write('44444\n')
     f.write('55555\n')
#强调 w 模式与 a 模式的异同:
# 1 相同点:在打开的文件不关闭的情况下,连续的写入,新写的内容总会跟在前写的内容之后
# 2 不同点:以 a 模式重新打开文件,不会清空原文件内容,会将文件指针直接移动到文件末尾,新写的内容永远写在最后
# a 模式用来在原来的文件内存的基础上写入新的内容,比如记录日志,注册功能。

# 小练习:实现注册功能:
# 为什么不能用w模式写呢,w都清空原来文件了,你原来用户都消失了,能这么干吗?
name=input('username>>>: ').strip()
pwd=input('password>>>: ').strip()
with open('db1.txt',mode='a',encoding='utf-8') as f:
    info='%s:%s\n' %(name,pwd)
    # info = f"{name}:{pwd}"
    f.write(info)
py# 用户注册,判定用户是否注册,提示用户已注册还是未注册,密码长度6--12.
name=input('username>>>: ').strip()
pwd=input('password>>>: ').strip()
with open("db.txt",mode="rt",encoding="utf-8") as f1:
    for line in f1:
        user, pwd1= line.strip().split(":")
        if name == user:
            print('用户已注册')
            break
    else:
        print(f"{name}可以注册")
        if 6<=len(pwd)<=12:
            with open("db.txt", mode="at", encoding="utf-8") as f2:
                f2.write(f"{name}:{pwd}\n")
        else:
            if len(pwd) <6:
                print("密码长度小于6位")
            else:
                print("密码长度大于12位")

案例四:+ 模式的使用(了解)

# r+ w+ a+ :可读可写
#在平时工作中,我们只单纯使用r/w/a,要么只读,要么只写,一般不用可读可写的模式
adeng01.txt文件内容:adeng:123456

with open(r"adeng01.txt",mode="r+", encoding="utf-8") as f:
    f.write("ren") # r+写入不会清空,但是会覆
# 写入后覆盖了ade 变成了 renng:123456

2.控制文件读写内容的模式

重点对待:

大前提: tb模式均不能单独使用,必须与r/w/a之一结合使用
t(默认的):文本模式
    1. 读写文件都是以字符串为单位的
    2. 只能针对文本文件
    3. 必须指定encoding参数
b:二进制模式:
   1.读写文件都是以bytes/二进制为单位的,任何文件都可以用b模式读取或写入
   2. 可以针对所有文件
   3. 一定不能指定encoding参数

案例一:t 模式的使用

# t 模式:如果我们指定的文件打开模式为r/w/a,其实默认就是rt/wt/at
 with open('a.txt',mode='rt',encoding='utf-8') as f:
     res=f.read() 
     print(type(res)) # 输出结果为:

 with open('a.txt',mode='wt',encoding='utf-8') as f:
     s='abc'
     f.write(s) # 写入的也必须是字符串类型

 #强调:t 模式只能用于操作文本文件,无论读写,都应该以字符串为单位,而存取硬盘本质都是二进制的形式,
 当指定 t 模式时,内部帮我们做了编码与解码

案例二: b 模式的使用

# b: 读写都是以二进制位单位
with open(r'美女.png',mode='rb') as f:
    data=f.read()
    print(data,type(data)) # 输出结果为:

with open(r'aa.txt',mode='wb') as f:
    msg="你好"
    res=msg.encode('utf-8') # res为bytes类型,wb模式字符串写入到硬盘需要encode编码
    f.write(res) # 在b模式下写入文件的只能是bytes类型

#强调:b模式对比t模式
1、在操作纯文本文件方面t模式帮我们省去了编码与解码的环节,b模式则需要手动编码与解码,所以此时t模式更为方便
2、针对非文本文件(如图片、视频、音频等)只能使用b模式

# 小练习: 编写拷贝工具
src_file=input('源文件路径: ').strip()
dst_file=input('目标文件路径: ').strip()
with open(r'%s' %src_file,mode='rb') as read_f,open(r'%s' %dst_file,mode='wb') as write_f:
    for line in read_f: # 循环读取文件
        # print(line)
        write_f.write(line)

七、操作文件的方法

重点对待

# 读操作
f.read()  # 读取所有内容,执行完该操作后,文件指针会移动到文件末尾
f.readline()  # 读取一行内容,光标移动到第二行首部
f.readlines()  # 读取每一行内容,存放于列表中

# 强调:
# f.read()与f.readlines()都是将内容一次性读入内容,如果内容过大会导致内存溢出,若还想将内容全读入内存,则必须分多次读入,有两种实现方式:
# 方式一
with open('a.txt',mode='rt',encoding='utf-8') as f:
    for line in f:
        print(line) # 同一时刻只读入一行内容到内存中

# 方式二
with open('1.mp4',mode='rb') as f:
    while True:
        data=f.read(1024) # 同一时刻只读入1024个Bytes到内存中
        if len(data) == 0:
            break
        print(data)

# 写操作
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模式

bytes===>二进制

  1. 字符串编码encode之后的结果
  • "字符串".encode("utf-8")
  • bytes("字符串",encoding="utf-8")
  1. b"必须是纯英文字符"
  2. b模式下打开文件,读取的内容

用处:可以存到硬盘里面去

循环读取文件的两种方式:

# 方式一: 
with open('a.txt',mode='rt',encoding='utf-8') as f:
    for line in f:
        print(line) # 同一时刻只读入一行内容到内存中
        
 # 方式二 一行读取的内容很多时候,大文件采取的策略
with open('1.mp4',mode='rb') as f:
    while True:
        data=f.read(1024) # 同一时刻只读入1024个Bytes到内存中
        if len(data) == 0:
            break
        print(data)
        
# 方式三 读取一行,这个和方式一差不多。选择一吧 这个知道就行。for循环比while循环速度快    
with open('1.mp4',mode='rb') as f:
    while True:
        data=f.readline()
        if len(data) == 0:
            break
        print(data)

了解

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

八、主动控制文件内指针移动seek()

  • 文件内指针的移动都是Bytes/字节为单位的,唯一例外的是t模式下的read(n),n以字符为单位
#大前提:文件内指针的移动都是Bytes/字节为单位的,唯一例外的是t模式下的read(n),n以字符为单位
with open('a.txt',mode='rt',encoding='utf-8') as f:
     data=f.read(3) # 读取3个字符


with open('a.txt',mode='rb') as f:
     data=f.read(3) # 读取3个Bytes

with open('c.txt',mode='rt') as f:
    # f.seek(1,1) # t 模式不能在 1模式 使用
    f.seek(1,2)   # t 模式不能在 2模式 使用
    
 # 文件xx.txt有 12字节
f.seek(1,0)
f.seek(2,0)
f.seek(3,0)
# 最终的位置是 3
f.seek(1,1)
f.seek(2,1)
f.seek(3,1)
# 最终的位置是1+2+3 =6
f.seek(-1,2)
f.seek(-2,2)
f.seek(-3,2)
# 最终的位置是文件末尾向左移动3个字节的位置,文件有12个字节这里就是 9

# 之前文件内指针的移动都是由读/写操作而被动触发的,若想读取文件某一特定位置的数据,则则需要用f.seek方法主动控制文件内指针的移动,详细用法如下:
# f.seek(指针移动的字节数,模式控制): 
# 模式控制:
# 0: 默认的模式,该模式代表指针移动的字节数是以文件开头为参照的
# 1: 该模式代表指针移动的字节数是以当前所在的位置为参照的
# 2: 该模式代表指针移动的字节数是以文件末尾的位置为参照的
# 强调:其中0模式可以在t或者b模式使用,而1跟2模式只能在b模式下用

案例一: 0模式详解

# a.txt用utf-8编码,内容如下(abc各占1个字节,中文“你好”各占3个字节)
abc你好

# 0模式的使用
with open('a.txt',mode='rt',encoding='utf-8') as f:
    f.seek(3,0)     # 参照文件开头移动了3个字节
    print(f.tell()) # 查看当前文件指针距离文件开头的位置,输出结果为3
    print(f.read()) # 从第3个字节的位置读到文件末尾,输出结果为:你好
    # 注意:由于在t模式下,会将读取的内容自动解码,所以必须保证读取的内容是一个完整中文数据,否则解码失败

with open('a.txt',mode='rb') as f:
    f.seek(6,0)
    print(f.read().decode('utf-8')) #输出结果为: 好

案例二: 1模式详解

# 1模式的使用
with open('a.txt',mode='rb') as f:
    f.seek(3,1) # 从当前位置往后移动3个字节,而此时的当前位置就是文件开头
    print(f.tell()) # 输出结果为:3
    f.seek(4,1)     # 从当前位置往后移动4个字节,而此时的当前位置为3
    print(f.tell()) # 输出结果为:7

案例三: 2模式详解

# a.txt用utf-8编码,内容如下(abc各占1个字节,中文“你好”各占3个字节)
abc你好

# 2模式的使用
with open('a.txt',mode='rb') as f:
    f.seek(0,2)     # 参照文件末尾移动0个字节, 即直接跳到文件末尾
    print(f.tell()) # 输出结果为:9
    f.seek(-3,2)     # 参照文件末尾往前移动了3个字节
    print(f.read().decode('utf-8')) # 输出结果为:好

# 小练习:实现动态查看最新一条日志的效果
import time
with open('access.log',mode='rb') as f:
    f.seek(0,2)
    while True:
        line=f.readline()
        if len(line) == 0:
            # 没有内容
            time.sleep(0.5)
        else:
            print(line.decode('utf-8'),end='')

文件追加写入,然后动态查看最新一条日志的效果

#文件追加.py的代码
import random
import time

for i in range(10):
    with open("access.log",mode="at", encoding="utf-8") as f:
        f.write(f"xxx{random.randint(1,100000)}下班了,阿登今天不加班\n")
        time.sleep(1.5)
        pass
#  此文件追加写入access.log,tail -f.py负责动态实时查看
------------------------------------------------------------------------------------
 #tail -f.py的代码
import time
# 模仿 tail -f XXX.log 实现动态查看最新一条日志的效果


with open("access.log",mode="rb") as f:
    f.seek(0,2) # 检测文件末尾.2模式只能b模式用
    while True:
        line = f.readline()
        if not line:
            # 没有日志写入
            time.sleep(1)
        else:
            print(line.decode("utf-8"),end=" ")




九、修改文件的两种方式:

# 文件d.txt内容如下
张一蛋     山东    179    49    12344234523
李二蛋     河北    163    57    13913453521
王全蛋     山西    153    62    18651433422

# 执行操作
with open('d.txt',mode='r+t',encoding='utf-8') as f:
    f.seek(9)
    f.write('<妇女主任>')

# 文件修改后的内容如下
张一蛋<妇女主任> 179    49    12344234523
李二蛋     河北    163    57    13913453521
王全蛋     山西    153    62    18651433422

# 强调:
# 1、硬盘空间是无法修改的,硬盘中数据的更新都是用新内容覆盖旧内容
# 2、内存中的数据是可以修改的.

文件修改方式一

# 实现思路:将文件内容发一次性全部读入内存,然后在内存中修改完毕后再覆盖写回原文件
# 优点: 在文件修改过程中同一份数据只有一份
# 缺点: 会过多地占用内存
"""
e.txt的内容如下:
阿登一个单身就是想找个小姐姐谈恋爱。
找个小姐一定得爱着阿登哥哥!!!
如果加个爱阿登的期限:
□□□□□□□□□一万年!!!□□□□□□□

"""
with open('e.txt',mode='rt',encoding='utf-8') as f:
    data=f.read()

with open('e.txt',mode='wt',encoding='utf-8') as f:
    f.write(data.replace('阿登','向佳'))

文件修改方式二

# 实现思路:以读的方式打开原文件,以写的方式打开一个临时文件,一行行读取原文件内容,修改完后写入临时文件...,删掉原文件,将临时文件重命名原文件名
# 优点: 不会占用过多的内存
# 缺点: 在文件修改过程中同一份数据存了两份
import os
with open('e.txt',mode='rt',encoding='utf-8') as f1,\
    open("e01.txt", mode="wt", encoding="utf-8") as f2:
    for line in f1:
        f2.write(line.replace("阿登","向佳"))
os.remove("e.txt")
os.rename("e01.txt", "e.txt")

文件修改方式三:参考

# 方式一修改文件:读出内容修改---清空--写入
with open(r"e.txt",mode="rb+") as f1:
    data = f1.read()
    # 对读出来的内容进行解码
    data = data.decode("utf-8").replace("阿登","向佳")
    print(data)
    # 指针指定到开头
    f1.seek(0,0)
    # 清空 truncate
    f1.truncate()
    f1.write(data.encode("utf-8"))

总结文件对象方法:

文件对象方法
f.read() 有参数表从开头读多少个字节,没有读取所有内容。读小文件推荐
f.readline() 读取一行内容,光标移动到第二行首部.读大文件推荐,或者 for line in 遍历
f.readlines() 读取每一行内容,存放于列表中.返回值是一个列表包含'\n'.读小文推荐
f.write() f.write('1111\n222\n') #针对文本模式的写,需要自己写换行符。内容必须是 字符串
f.write() f.write('1111\n222\n'.encode('utf-8')) #针对b模式的写,需要自己写换行符。返回是int 字符数
f.writelines() f.writelines(['333\n','444\n']) #文本模式。列表元素必须是 字符串
f.writelines() f.writelines([bytes('333\n',encoding='utf-8'),'444\n'.encode('utf-8')]) #b模式
f.seek(x,y) seek(x, 0):从开始位置向右 x 个字符
f.seek(x,y) seek(x, 1):当前位置往右移动 x 个字符
f.seek(x,y) seek(-x, 2):文件的结尾向左移动 x 个字符
f.tell() 返回文件的当前位置
f.truncate() 清空文件,配合f.seek(0) 使用,调整指针位置。
f.closed 文件是否关闭
f.flush() 立刻将文件内容从内存刷到硬盘
f.readable() 文件是否可读
f.writable() 文件是否可写
f.name 文件名字

你可能感兴趣的:(py_13文件操作和方法)