文件处理

一 引入

应用程序运行过程中产生的数据最先都是存放于内存中的,若想永久保存下来,必须要保存于硬盘中。应用程序若想操作硬件必须通过操作系统,而文件就是操作系统提供给应用程序来操作硬盘的虚拟概念,用户或应用程序对文件的操作,就是向操作系统发起调用,然后由操作系统完成对硬盘的具体操作。

二 文件的介绍

2.1 文件的概念

文件:就是操作系统显示给用户可以直接操作硬盘的快捷方式

文件的类型:txt word excel py

有了文件的概念,我们无需再去考虑操作硬盘的细节,只需要关注操作文件的流程:

# 代码打开的两种方式:
# 方式1:
f=open('a.txt', 'r', encoding='utf-8')
# 是让操作系统打开文件,代码只是发出指令
# print(f)  # <_io.TextIOWrapper name='a.txt' mode='r' encoding='utf8'>  文件句柄
# 2.操作文件
print(f.read())  # 读出a.txt文件中的内容
# 3.关闭文件
f.close() 

# 方式2:
# 2. with上下文管理器
with open(r'D:\python25\day09\a.txt', 'r', encoding='utf-8') as f2:
    print(f2.read()) # 自动关闭文件

open关键字:

"""
	语法格式:
		open('文件路径', '读写模式', '字符编码')

	        '文件路径', '读写模式'是必须要写的
        	encoding是可选的
"""

2.1 文件路径

# open寻找文件的方式:先在当前文件中寻找文件名,所以,如果是当前文件中,‘文件路径’可以直接写相对路径,如果是其他文件中,必须写绝对路径

open(r'a.txt', 'r', encoding='utf-8')  # 相对路径
open(r'F:\pr\py\a.txt', 'r', encoding='utf-8')  # 绝对路径


'''
    r的作用:
        当路径中可能存在有转义的字符时,字符串前面加上r来解决转义的问题
'''

三、文件的操作模式

3.1 文件的读写模式

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

3.1.1 r模式

r>>> read: 只读 # 只能读,不能写
路径不存在时,报错
路径存在,正常打开文件

with open(r'a.txt', 'r', encoding='utf-8') as f:
    print(f.read())

3.1.2 w模式

w>>> write:只写 # 只能写,不能读
文件路径不存在时,自动创建。文件路径存在时 先清空文件内容之后在写入

with open('b.txt', 'w', encoding='utf-8') as f:
    pass

# 2.1 会先清空文件中的内容(只要点击Run就会清空文件)2. 再进行写内容
'''写文件的是一定要小心,它会清空文件的'''
with open('a.txt', 'w', encoding='utf-8') as f:
    f.write('oldboy\n')  #运行多次,文件中也只有一行

      
# 2.2文件中想要写多行
with open('a.txt', 'w', encoding='utf-8') as f:
    f.write('oldboy\n')
    f.write('oldboy\n')
    f.write('oldboy\n')
    f.write('oldboy\n')
'''  在多行一起write时,如果不使用分隔符分割,都会输出在一行里面,不会帮你自动分割,想要换行我们必须自己加入\n分隔符'''

3.1.3 a 模式

a >>> append: 追加
路径不存在时,自动创建文件,路径存在时,不会清空文件内容,而是在文件末尾等待新内容的添加

with open('a.txt', 'a', encoding='utf-8') as f:
    f.write('oldgirl\n')

3.2 控制文件读写内容的模式

r w a读取

大前提: tb模式均不能单独使用,必须与r/w/a之一结合使用
t(默认的):文本模式
    1. 只能操作文本文件
    2. 都是以字符为单位
    3. rt wt at  => t可以省略
    4. encoding参数必须写 
		
b模式:二进制
    1. 能操作任何的数据类型,eg:文本,视频,音频...
    2. 写法:rb ab wb  >>>: 此时的b不能省略
    3. encoding参数不写
    4. 就是以字节为单位

3.2.1 案例一: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)) 
# 输出结果为:<class 'str'>
        
 with open('a.txt',mode='wt',encoding='utf-8') as f:
     s='abc'
     f.write(s) # 写入的也必须是字符串类型
    
 #强调:t 模式只能用于操作文本文件,无论读写,都应该以字符串为单位,而存取硬盘本质都是二进制的形式,当指定 t 模式时,内部帮我们做了编码与解码

3.2.2 案例二: b 模式的使用

# 用二进制的模式将'你好'写入'b.txt'文件
with open('b.txt', 'wb') as f:
    s = '你好'
    f.write(s.encode('utf8'))

# 读取'b.txt'文件
with open('b.txt', 'rb') as f:
    print(f.read().decode('utf8'))

四、文件的操作方法

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

# 写
f.write('hello\n')  # 写入内容到文件
f.writable()  # 是否可写
f.writelines(['333\n','444\n'])  # 写入多行到文件中,要以列表形式

4.1 读方法

4.1.1 读取的不同用法

# 用法1:
with open(r'a.txt', 'r', encoding='utf-8') as f:
print(f.read())
# 输出:
# oldboy
# oldboy
# oldboy

# 用法2:
with open(r'a.txt', 'r', encoding='utf-8') as f:
    data = f.read()
    print(data)
print(data)  # 用with,后面的代码也可以使用with里定义的数据
# 输出:
# oldboy
# oldboy
# oldboy
# oldboy
# oldboy
# oldboy

4.1.2 read()

with open(r'a.txt', 'r', encoding='utf-8') as f:
    print(f.read())  # 一次性读取文件内所有的数据
    print(f.read())  # 后面两行读取的是空格
    print(f.read())

'''一次性读取文件所有的数据就会存在漏洞:导致内存溢出'''

4.1.3 readline()

with open(r'a.txt', 'r', encoding='utf-8') as f:
    print(f.readline())  # 一次读取一行,输出内容会有空格,因为txt文件中的数据换行后默认存在一个换行符,而一个换行符也属于一个字符串格式,实际上第一行数据是('oldboy\n')
    print(f.readline())  # 一次读取一行
    print(f.readline())  # 一次读取一行

4.1.4 readlines()

'''把文件内的一行一行数据组装成列表元素返回,注意末尾的换行符'''
with open(r'a.txt', 'r', encoding='utf-8') as f:
        print(f.readlines()) 
# 输出:['你好洋哥\n', '你好洋哥\n', '你好洋哥\n']
     

4.1.5 readable()

# 是否可读,布尔值
with open(r'a.txt', 'r', encoding='utf-8') as f:
    print(f.readable())  # True

4.2 写方法

4.2.1 write('hello\n')

with open('a.txt', 'w', encoding='utf-8') as f:
    f.write('hello\n')
    f.write('hello\n')
    f.write('hello\n')

4.2.2 writable()

with open('a.txt', 'w', encoding='utf-8') as f:
    print(f.writable()) # True
    print(f.readable())  # False

4.2.3 writelines()

with open('a.txt', 'w', encoding='utf-8') as f:
    print(f.writelines(['你好洋哥1\n', '你好洋哥2\n', '你好洋哥3\n']))

五、文件读操作优化

5.1 for循环一行一行读取

with open('a.txt', 'r', encoding='utf-8') as f:
    print(f.read())

    '''文件句柄f支持for循环'''
    for line in f:
        print(line)  # 一次代码一行数据

    '''以后读取文件数据的时候,都使用for循环去一行一行的读取,不会出现内存溢出的情况'''

5.2 flush()

# flush():把内存中得数据立刻刷到硬盘中
with open('a.txt', 'w', encoding='utf-8') as f:
    f.write('hello')
    f.flush() 

六、文件二进制读操作(了解)

    1. r模式
        read()里面的数字代表的是一个字符
    2. b模式
        read()里面的数字代表的是一个字节

练习如下:

# # 用r模式读取文件
# with open('a.txt', 'r', encoding='utf-8') as f:
#     print(f.read())

# # 用二进制rb模式读取文件
# with open('a.txt', 'rb') as f:
#     print(f.read().decode('utf-8'))

with open(r'a.txt', 'r', encoding='utf-8') as f:
    print(f.read(4))
# 输出结果:你hel

with open(r'a.txt', 'rb') as f:
    # print(f.read(4))  # b'\xe4\xbd\xa0h'
    # 不加解码,输出是二进制。加上解码,才能看出是什么字节
    print(f.read(4).decode('utf-8'))
# 输出结果:你h
'''1个中文汉字占用3个bytes, 如果文件中第一个是汉字,你read()中的数字<3,就会报错,因为不能将汉字拆分'''

七、文件的指针移动(了解)

    f.seek可以控制指针移动,总共有3种模式:
        1. offset参数
            偏移量,移动的位置
            如果是正数,从左往右读取
            如果是负数,从右往左读取
        2. whence参数
            # 0: 默认的模式,该模式代表指针移动的字节数是以文件开头为参照的
            # 1: 该模式代表指针移动的字节数是以当前所在的位置为参照的
            # 2: 该模式代表指针移动的字节数是以文件末尾的位置为参照的

7.1 0模式

# 0模式
with open('a.txt', 'rb') as f:
    print(f.read().decode('utf-8'))
    f.seek(3, 0)
    print(f.read().decode('utf-8'))
# 输出结果是:
# helloword
# mynameiskevin
# loword
# mynameiskevin

7.2 1模式

# 1模式
with open('a.txt', 'rb') as f:
    print(f.read(3).decode('utf-8'))
    f.seek(3, 1)
    print(f.read().decode('utf-8'))
# 输出结果是:
# hel
# ord
# mynameiskevin

7.3 2模式

# 2模式 
with open('a.txt', 'rb') as f:
    print(f.read(3).decode('utf-8'))
    f.seek(-3, 2)
    print(f.read().decode('utf-8'))
# 输出结果是:
# hel
# vin

# 小练习:实现动态查看最新一条文件的效果
import time
with open(r'a.txt', 'rb') as f:
    f.seek(0, 2)  # 指针移动到末尾,移动0个bytes
    while True:
        line = f.readline()  # 读取一行
        if len(line) == 0:
            # 如果没有内容,停0.5秒
            time.sleep(0.5)  # 停留0.5秒
        else:  # 如果有内容,打印数据
            print(line.decode('utf-8'), end='')

# 运行后光标一直在闪,在a.txt文件中输入内容,保存(ctrl+s),后面输的代码就会被输出

八、文件的修改(了解)

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

# 执行操作
with open('a.txt',mode='r+t',encoding='utf-8') as f:  # 'r+'模式:可读可写
    f.seek(9)  # 默认0模式
    f.write('<妇女主任>')
    
# 文件修改后的内容如下
张一蛋<妇女主任> 179    49    12344234523
李二蛋     河北    163    57    13913453521
王全蛋     山西    153    62    18651433422

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

文件对应的是硬盘空间,硬盘不能修改对应着文件本质也不能修改,
那我们看到文件的内容可以修改,是如何实现的呢?

大致的思路是将硬盘中文件内容读入内存,然后在内存中修改完毕后再覆盖回硬盘
具体的实现方式分为两种:

8.1 文件的修改方式一

# 实现思路:将文件内容发一次性全部读入内存,然后在内存中修改完毕后再覆盖写回原文件
# 优点: 在文件修改过程中同一份数据只有一份
# 缺点: 会过多地占用内存


# 1. 读取b.txt文件数据
with open('b.txt', 'r', encoding='utf-8') as f:
    data = f.read()
print(data)  # kevin kevin kevin kevin say hello world
new_data = data.replace('kevin', 'jack')

# 2. 把新的数据再次写入文件
with open('b.txt', 'w', encoding='utf-8') as f1:
    f1.write(new_data)

8.2 文件的修改方式二

# 实现思路:以读的方式打开原文件,以写的方式打开一个文件,一行行读取原文件内容,修改完后写入新文件中...,删掉原文件,将新文件重命名原文件名
# 优点: 不会占用过多的内存
# 缺点: 在文件修改过程中同一份数据存了两份


import os

with open('a.txt', 'rt', encoding='utf-8') as read_f:
    with open('b.txt', mode='wt', encoding='utf-8') as write_f:
        for line in read_f:
            write_f.write(line.replace('jack', 'kevin'))

os.remove('a.txt')  # 删除源文件
os.rename('b.txt', 'a.txt')  # 文件重命名


# 可以用一个with同时打开两个文件,代码如下:
# with open('a.txt', 'rt', encoding='utf-8') as read_f, open('b.txt', mode='wt', encoding='utf-8') as write_f:
#     for line in read_f:
#         write_f.write(line.replace('jack', 'kevin'))

posted @ 2023-02-22 21:10  星空看海  阅读(41)  评论(0编辑  收藏  举报