文件操作

一.前言

  • 什么是文件?
    文件是操作系统暴露给用户操作硬盘的快捷方式

内存中存放的数据在计算机关机后就会消失。要长久保存数据,就要使用硬盘、光盘、U 盘等设备。
应用程序若想操作硬件必须通过操作系统,而文件就是操作系统提供给应用程序来操作硬盘的虚拟概念,用户或应用程序对文件的操作,就是向操作系统发起调用,然后由操作系统完成对硬盘的具体操作。
image

二.在python中打开/关闭文件

open方法

open()返回一个文件对象,最常使用的是两个位置参数和一个关键字参数:
open(filename, mode, encoding=None)

# 1.使用open函数,相当于python解释器跟操作系统说我要打开a.txt文件,操作系统找到a.txt在硬盘中存放的位置,打开a.txt,占用一定资源,再返回一个文件对象,通过操作这个文件对象,我们就可以操作硬盘中的文件了。我们用变量名f跟这个文件对象绑定,方便调用。
f = open('a.txt','r',encoding='utf-8')  # 以 r模式 utf-8解码 打开硬盘中的 a.txt文件

# 2. 调用文件对象下的读/写方法,会被操作系统转换为读/写硬盘的操作
print(f.read())  # read是文件对象的内置方法

# 3.向操作系统发起关闭文件的请求,回收系统资源
f.close()  # 告诉操作系统 这个文件我不用了 操作系统会将f对应的文件关闭

close资源回收

打开一个文件包含两部分资源:python解释器中的变量f和操作系统打开的文件。

  1. f.close()关掉操作系统打开的文件
  2. del f删除变量f
f = open('data.txt', 'r', encoding='utf8')  
f.close()
print(f)  # <_io.TextIOWrapper name='data.txt' mode='r' encoding='utf8'>
print(f.read())  # ValueError: I/O operation on closed file.  # f.close之后无法再使用这个文件,因为操作系统已经把文件关了
del f  # 删除变量名f python垃圾回收机制也会帮助我们做这件事

请注意:f.close()是必须的,如果不关闭,这个文件就会一直在打开的状态,占用资源。del f一定要发生在f.close()之后,否则也会导致操作系统打开的文件无法关闭。

with上下文管理 (推荐使用)

python中提供with关键字供我们进行资源回收管理。with的子句体结束后,即便触发异常,文件也可以正常关闭。

# 1、在执行完子代码块后,with 会自动执行f.close()
with open('a.txt','w') as f:
    print(f.closed)  # False  # f.closed查看文件是否关闭
print(f.closed)  # True
 
# 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)

三.文件的操作模式

image

r模式的使用

# 1.路径中没有指定的文件 会直接报错 文件存在时,文件内指针直接跳到文件开头
with open('a.txt', 'r', encoding='utf-8') as f :
    pass  # FileNotFoundError: [Errno 2] No such file or directory: 'a.txt'
# 2.只能读不能写
with open('a.txt', 'r', encoding='utf-8') as f :
 	f.write('hello')  # io.UnsupportedOperation: not writable
# 3.读一下文件吧
with open('a.txt','r',encoding='utf-8') as f:
     data = f.read() # 会将文件的内容由硬盘全部读入内存,赋值给data

w模式的使用

# 1.路径中没有指定的文件时 会创建一个新文件 文件存在会清空文件 文件指针跑到文件开头
with open('b.txt',mode='w',encoding='utf-8') as f:
    f.write('hello')
    f.write('world')  # helloworld  
                      # 在文件不关闭的情况下,连续的写入,后写的内容一定紧跟在前写内容的后面
with open('b.txt',mode='w',encoding='utf-8') as f:  # 再次打开b.txt
    f.write('hi')  # 此时文件中的内容会变成hi
# 2.只写模式不能读
# 会报错:io.UnsupportedOperation: not readable

a模式的使用

# 1.a可记为append 当文件存在时 他会直接接着后面写入 文件不存在时 也会创建一个新文件
with open('c.txt',mode='a',encoding='utf-8') as f:
     f.write('hello')
# a模式不会清空文件内容 他会把光标移动到文件末尾 然后开始进行写的操作 a模式也是只能写不能读

+模式的使用

# r+ w+ a+ :可读可写
# 在平时工作中,我们只单纯使用r/w/a,要么只读,要么只写,一般不用可读可写的模式

b模式的使用 (重要)

# 模式的使用 b模式是二进制模式 所有的图片视频音频都只能使用该模式
with open('img.png', 'rb') as f:  # 使用二进制只读模式rb 打开一张图片
    data = f.read()
    print(data)  # b'\x89PNG\r\n\x1a\n\x00\x00\x00\r.... # bytes类型的数据
    print(type(data))  # <class 'bytes'> 可看成二进制

操作文件的方法

读文件

image

# 1.使用for循环
with open('a.txt', mode='rt', encoding='utf-8') as f:
    for line in f:
        print(line, end='')  # 同一时刻只读入一行内容到内存中
        # 结果会出现很多的换行符 因为每行末尾都会有一个看不见的换行符 print也会自带一个换行符
        # 可使用line.rstrip # print(line.rstrip('\n'))
		
# 2.使用read(1024)
with open('img.png',mode='rb') as f:
     while True:
        data=f.read(1024) # 同一时刻只读入1024个Bytes到内存中
        if len(data) == 0:
            break
        print(data)

写文件

image

额外的方法

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

控制文件内光标的移动

seek方法

image

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

# 3.以二进制模式打开
with open('test.txt', mode='rb') as f:
    f.seek(6, 0)  # 0表示:0模式
    print(f.read().decode('utf-8'))  # 输出结果为: 好 # 二进制模式所以要解码

# 4.以1模式 从当前位置
with open('test.txt', mode='rb') as f:  # abc3个字节 你好6个字节
    print(f.read().decode('utf8'))  # read之后光标会移动到末端
    f.seek(0)
    f.seek(3, 1)  # 从当前位置往后移动3个字节,而此时的当前位置就是文件开头
    print(f.tell())  # 输出结果为:3
    f.seek(4, 1)  # 从当前位置往后移动4个字节,当前位置为3
    print(f.tell())  # 输出结果为:7
    # print(f.read().decode('utf8'))  # 会报错 因为光标(7)卡在汉字的三个字节之间 相当于数据不是完整的 导致汉字无法解码
	
# 5.以2模式 从末尾
with open('test.txt',mode='rb') as f:
    print(f.tell())  #文件刚打开光标还是在开头 但是seek会从末尾开始移动 seek(0)代表末尾
    f.seek(0,2)     # 参照文件末尾移动0个字节, 即直接跳到文件末尾
    print(f.tell()) # 输出结果为:9
    f.seek(-3,2)     # 参照文件末尾往前移动了3个字节 刚好移动到‘好’这个字前面
    print(f.read().decode('utf-8')) # 输出结果为:好

t模式下的read是以字符为单位(了解)

# 大前提:文件内指针的移动都是Bytes为单位的,唯一例外的是t模式下的read(n),n以字符为单位
with open('test.txt', mode='rt', encoding='utf-8') as f:
    data = f.read()  # 读取4个字符  
print(data,type(data)) # abc你 <class 'str'>
#
with open('test.txt', mode='rb') as f:
    data = f.read(6)  # 读取6个Bytes
print(data.decode('utf8'),type(data)) # abc你 <class 'bytes'>

文件内容的修改(了解)

# 修改文件内容的方式1:覆盖写
# with open(r'a.txt', 'r', encoding='utf8') as f:
#     data = f.read()
# with open(r'a.txt', 'w', encoding='utf8') as f1:
#     f1.write(data.replace('jason', 'tony'))

# 修改文件内容的方式2:换地写
'''先在另外一个地方写入内容 然后将源文件删除 将新文件命名成源文件'''
import os

with open('a.txt', 'r', encoding='utf8') as read_f, \
        open('.a.txt.swap', 'w', encoding='utf-8') as write_f:
    for line in read_f:
        write_f.write(line.replace('tony', 'kevinSB'))


os.remove('a.txt')  # 删除a.txt
os.rename('.a.txt.swap', 'a.txt')  # 重命名文件
posted @ 2022-10-08 22:40  passion2021  阅读(58)  评论(0编辑  收藏  举报