返回顶部

python文件操作

一.文件操作流程

# 1. 打开文件,由应用程序向操作系统发起系统调用open(...),操作系统打开该文件,对应一块硬盘空间,并返回一个文件对象赋值给一个变量f
f = open('a.txt',mode='r',encoding='utf-8') #默认打开模式就为r
 
# 2. 调用文件对象下的读/写方法,会被操作系统转换为读/写硬盘的操作
data = f.read()
 
# 3. 向操作系统发起关闭文件的请求,回收系统资源
f.close()

二.资源回收和with上下文管理

1、f.close()  # 回收操作系统打开的文件资源
2del f  # 回收应用程序级的变量
  • with上下文管理
# 1、在执行完子代码块后,with 会自动执行f.close()
with open('a.txt',mode='w', encoding='utf-8') as f:
    pass 
 
# 2、可用用with同时打开多个文件,用逗号分隔开即可
with open('a.txt',mode='r',encoding='utf-8') as read_f,\
		open('b.txt',mode='w', encoding='utf-8') as write_f:  
    data = read_f.read()
    write_f.write(data)

三.指定操作文本文件的字符编码(在t模式下, 必须要指定字符编码)

'''

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

'''

# 没有指定encoding参数操作系统会使用自己默认的编码
# linux系统默认utf-8
# windows系统默认是gbk

with open('a', mode='rt', encoding='utf-8') as f:
    result = f.read()  # t模式会将f.read()读出的结果解码成unicode(内存中)
    print(result)

# 内存: utf-8格式的二进制---解码--->unicode
# 硬盘(a内容: utf-8格式的二进制)

四.文件操作模式

4.1控制文件读写的操作

r(默认的):只读
w:只写
a:只追加写

4.1.1r模式+案例

# 1. r(默认的操作模式) : 只读模式, 当文件不存在时报错, 当文件存在时文件指针跳到开始位置
with open('aaa/a', mode='rt', encoding='utf-8') as f:
    print('第一次读'.center(10, '-'))
    result = f.read()  # 把所有内容从硬盘读入内存
    print(result)

# 案例
temp = True
list1 = []
while temp:
    in_username = input('your name>> ').strip()
    in_password = input('your pwd>> ').strip()
    list1.append(in_username)
    with open('aaa/bbb', mode='rt', encoding='utf-8') as f1:
        for line in f1:
            name, pwd = line.strip().split(':')  # stirp()是去掉字符串两边空白字符, 这里是解压赋值
            if in_username == name and in_password == pwd:
                print('login successful')
                temp = False
                break
        else:
            print('账号或者密码错误 ')  # for循环正常结束, 没有被break打断才会执行
            if len(list1) == 3:
                print('最多只能输入三次, 傻子')
                temp = False

4.1.2w模式+案例

# w: 只写模式, 当文件不存在时会创建空文件, 当文件存在时会清空文件, 指着位于开始位置

with open('aaa/ccc.txt', mode='wt', encoding='utf-8') as f:
    f.write('哈哈哈\n')  # \n表示的是换行
    # f.read()   # 会报错
    
# 在以w模式打开文件没有关闭的情况下, 连续写入, 新的内容总是跟在旧的之后
with open('aaa/ddd.txt', mode='wt', encoding='utf-8') as f:
    f.write('哈哈1\n')
    f.write('哈哈2\n')
    f.write('哈哈3\n')


# 案例: w模式用来创建全新的文件
# 文件的copy工具
src_file = input('源文件路径>>>: ').strip()
dst_file = input('源文件路径>>>: ').strip()

with open(f'{src_file}', mode='rt', encoding='utf-8') as f,\
        open(f'{dst_file}', mode='wt', encoding='utf-8') as f1:
    res = f.read()
    f1.write(res)

4.1.3a模式+案例

  • w 模式与a 模式的对比:
    1. 相同点: 再打开的文件不关闭的情况下, 连续的写入, 新写的内容会在跟在前写的内容之后
    2. 不同点: 以 a 模式重新打开文件, 不会清空原文件内容, 会将文件指针移动到文件末尾, 新写的内容永远写在最后
# 3.a 只追加写, 在文件不存在时会创建空文档, 当文件存在时指针会直接调到末尾
with open('aaa/ddd.txt', mode='at', encoding='utf=8') as f:
    f.write('哈哈哈哈哈哈\n')

# w 模式与a 模式的对比
# 1. 相同点: 再打开的文件不关闭的情况下, 连续的写入, 新写的内容会在跟在前写的内容之后
# 2. 不同点: 以 a 模式重新打开文件, 不会清空原文件内容, 会将文件指针移动到文件末尾, 新写的内容永远写在最后

# 案例: a 模式用在原有的文件基础之上写入新的内容, 比如记录日志, 注册
# 注册功能

name = input('your name: ').strip()
pwd = input('your pwd: ').strip()
with open('aaa/ddd.txt', mode='at', encoding='utf-8') as f:
    f.write(f'账户名:{name}, 密码:{pwd}\n')

4.1.4+模式

# + 不能单独使用, 必须配合r,w,a 可读可写
with open('aaa/a', mode='r+', encoding='utf-8') as f:
    print(f.read())
    print(f.write('123'))

4.2控制文件读写内容

"""
    控制文件读写内容的方式
    t:
        1.读写都是以字符串(unicode) 为单位
        2.只能针对文本文件
        3.必须指定字符编码, 即必须指定encoding参数
    b: binary模式
        1.读写都是以bytes为单位
        2.可以针对所有文件
        3.一定不能指定字符编码, 即一定不能指定encoding参数

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

"""

4.2.1t模式+案例

# 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 模式时,内部帮我们做了编码与解码


4.2.2b模式+案例

with open(r'列表循环删除.jpg', mode='rb') as f:
    result = f.read()  # 不能指定字符编码, 会报错的, 硬盘的二进制读入内存-->b模式, 不做任何转换, 直接读入内存
    print(result)  # bytes类型-->当成二进制
    print(type(result))

with open(r'a.txt', mode='rb') as f:
    result = f.read()
    print(result)  # b'aaa'
    print(type(result))
    print(result.decode('utf-8'))  # 通过解码获得结果


with open(r'a.txt', mode='wb') as f:
    f.write('你好hello'.encode('utf-8'))

# 文件拷贝工具
src_file = input('源文件路径>> ').strip()
dst_file = input('目标文件路径>> ').strip()
with open(fr'{src_file}', mode='rb') as f1, \
        open(fr'{dst_file}', mode='wb') as f2:
    for line in f1:
        f2.write(line)


# 循环读取文件
# 用while实现: 自己控控制每次读取的数据的数据量
with open(r'列表循环删除.jpg', mode='rb') as f:
    while True:
        result = f.read(1024)  # 1024个字节
        if len(result) == 0:
            break
        print(len(result))

4.2.3x模式

'''
    x模式(控制文件操作的模式)
    x , 只写模式[不可读, 不存在则创建, 存在则报错
'''

with open('a.txt', mode='x', encoding='utf-8') as f:
    f.write('aaa')

五.操作文件的方法

5.1(重点)

# 一. 读相关的操作
# read()
#	    1. 文件打开方式为文本模式时,代表读取n个字符
#    2. 文件打开方式为b模式时,代表读取n个字节
# 1.readline: 一次读一行,readline()读取出来的数据在后面都有一个\n
# 可以用strip()解决这个问题
with open(r'a.txt', mode='rt', encoding='utf-8') as f:
    res1 = f.readline()  # 读取一行
    print(res1)
    while True:
        line = f.readline()
        if len(line) == 0:
            break
        print(line)

# readlines() 返回一个列表,列表里面每个元素是原文件的每一行,如果文件很大,占内存,容易崩盘
with open(r'a.txt', mode='rt', encoding='utf-8') as f:
    res = f.readlines()  # ['你好hello\n', 'aaa\n', 'bbb\n', 'ccc']
    print(res)  # 默认的结果是列表

# f.read()和f.readlines()都是将内容一次性读入内存, 如果内容过大导致内存溢出,

# 二. 写相关的操作
# f.writelines()
with open(r'a.txt', mode='wt', encoding='utf-8') as f:
    # f.writelines('111\n222\n')
    list1 = ['111\n', '222\n', '333\n']
    # for line in list1:  # 循环列表写入
    #     f.write(line)
    f.writelines(list1)

with open('b.txt', mode='wb') as f:
    l = [
        '1111\n'.encode('utf-8'),
        '122\n'.encode('utf-8'),
        '333\n'.encode('utf-8')
    ]
    # 如果是纯英文字符, 可以直接加前缀b得到bytes类型
    l = [b'111', b'222', b'333']
    f.writelines(l)



5.2(了解)

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

六.控制文件指针移动

  • f.tell() 获取文件指针当前位置
    
    
# 大前提:文件内指针的移动都是Bytes为单位的,唯一例外的是t模式下的read(n),n以字符为单位
with open(r'a.txt', mode='rt', encoding='utf-8') as f:
    result = f.read(2)  # 提取2个字符
    print(result)
 
with open('a.txt',mode='rb') as f:
     data = f.read(3) # 读取3个Bytes
 
# 之前文件内指针的移动都是由读/写操作而被动触发的,若想读取文件某一特定位置的数据,则则需要用f.seek方法主动控制文件内指针的移动,详细用法如下:
# f.seek(指针移动的字节数,模式控制): 

# 模式控制:
# 0: 默认的模式,该模式代表指针移动的字节数是以文件开头为参照的
# 1: 该模式代表指针移动的字节数是以当前所在的位置为参照的
# 2: 该模式代表指针移动的字节数是以文件末尾的位置为参照的

# 强调:其中0模式可以在t或者b模式使用,而1跟2模式只能在b模式下用

6.1(0模式案例)

# 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')) #输出结果为: 好
    
with open('a.txt', mode='rb') as f:
    f.seek(2, 0)
    res = f.read()
    print(res.decode('utf-8'))
    print(f.tell())

6.2(1模式案例)

# 1模式的使用
# b模式不能指定字符编码

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

6.3(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='')


七.文件修改的两种方式

7.1方式一

# 方式一: 文本编辑采用的就是这种方式
# 实现思路: 将文件内容一次性全部读入内存, 然后在内存中修改完毕后再覆盖写回原文件
# 优点: 在文件修改的过程中同一份数据只有一份
# 缺点: 会过多占用内存
with open(r'a.txt', mode='r', encoding='utf-8') as f:
    res = f.read()  # 读取所有内容
    data = res.replace('西施', '小乔')  # 将内容修改, 赋值给变量存在内存中
with open(r'a.txt', mode='w', encoding='utf-8') as f1:
    f1.write(data)  # 覆盖写入硬盘

7.2方式二

# 方式二
# 要用到os模块
# 实现思路: 以读的方式打开原文件, 以写的方式打开一个临时文件, 一行行读取原文件内容,
#           修改完后写入临时文件, 删除原文件, 将临时文件名字改为原文件名字
# 优点: 不会占用过多的内存
# 缺点: 在文件修改过程中同一份文件存了两份, 占用硬盘内存

import os

with open(r'a.txt', mode='r', encoding='utf-8') as f, \
        open(r'.a.txt.swap', mode='w', encoding='utf-8') as f1:  # .'文件'.swap表示隐藏文件
    for line in f:
        f1.write(line.replace('小乔', '西施'))  # 循环写入
os.remove('a.txt')
os.rename('.a.txt.swap', 'a.txt')

八.seek的实例

8.1实时监控日志的增加的内容

"""
@作者:   roc小白
@ QQ:   845726666
@专栏:  https://www.cnblogs.com/jupeng/p/14939889.html
第一: 往文件里面写内容
"""
with open(r'a.txt', mode='a', encoding='utf-8') as f:
    f.write('\n大乔, 17 female')
    
    
# 二. 实时打印添加的内容
import time

with open(r'a.txt', mode='rb') as f:
    f.seek(0, 2)  # 指针移到末尾
    # 死循环, 一直读取最后一行数据
    while True:
        line = f.readline()
        if not line:
            time.sleep(0.3)
        else:
            print(line.decode('utf-8'), end='')
posted @   fuju  阅读(70)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示

目录导航