Python

Python文件操作

2020-08-06  本文已影响0人  xilifeng

一. 操作文件的三个步骤: 打开文件, 读写, 回收OS资源

1. 方式一: 打开文件, 读写, 回收OS资源

f = open(r"Y:\new\a.txt", mode="rt", encoding="utf-8")  # t读写文件的格式为字符串,open返回值文件对象/文件句柄,是程序的变量值
data = f.read()  # 硬盘上的文件内容读到内存中,OS根据指定的encoding把二进制数转成t(unicode字符串)给程序,t仅限文本文件
print(data, type(data))
f.close()  # close回收OS资源,close后不能再read,文件对象是程序的变量值,是程序的资源,仍然存在

2. 方式二: 上下文管理 with 会自动调用f.close(), f1.close(), f2...

with open(r"Y:\new\a.txt", mode="rt", encoding="utf-8") as f, \
        open(r"Y:\new\b.txt", mode="rt", encoding="utf-8") as f1:
    pass  # 也可以用...

二. 文件的打开模式

1. 控制文件读写操作的模式: r只读, w只写,擦写, a只追加写, +加上原没有的操作, r+, w+, a+: 读写

1.1 r: 只读, 不可写, 默认模式, 指针在文件开头

with open(r"Y:\new\a.txt", mode="rt", encoding="utf-8") as f:
    print(f.readable())  # True
    print(f.writable())  # False

1.2 w: 只写, 不可读, 创建一个新文档, 同名文件不存在则为创建, 同名文件存在则覆盖, 指针跳到文件开头

with open(r"Y:\new\b.txt", mode="wt", encoding="utf-8") as f:
    f.write("你好\nHello World.")
    f.write("打开文件不关的情况下,指针跟着移动,后续新写入的内容则是追加.但是文件关了重新打开,再写=擦写")

1.3 a: 只追加写,不可读,文件不存在则新建一个空文件;文件存在则不清空,无论是不是重新打开或关了,文件指针都跳到文件末尾,追加写入新内容

1.4 r+, w+, a+: 读写

2. 控制文件读写内容的模式, t,b须和r,w,a连用

2.1 t: 默认, 文本格式, 读写都是str字符串, 数字不可以, 仅限文本文件, 必须指定encoding参数

2.2 b: 原生格式, 读写都是bytes为单位, 能用于所有文件, 一定不能指定encoding参数

with open(r"Y:\new\a.txt", mode="wb") as f:
    f.write("原生格式写入新内容".encode("utf-8"))

3. 案例: 文件copy程序

src_file = input("源文件路径: ").strip()
dst_file = input("目标文件路径: ").strip()

with open(r"%s" % src_file, mode="rb") as f1, \
        open(r"%s" % dst_file, mode="wb") as f2:

3.1 方法一: 一次性读入内存

    data = f1.read()
    f2.write(data)

3.2 方法二: 逐行读取写入

    for line in f1:
        f2.write(line)

三. 文件内指针移动: seek是无IO操作的移动, read是有IO操作的被动移动

file.seek(移动的字节个数, 三种模式)  # 3种模式都以字节为移动单位

1. 三种模式:

1.1 模式 0 : 从文件开头为起点,f.seek(3, 0)从头往右移动3个字节

1.2 模式 1 : 从当前指针所在的位置,f.seek(6, 1)前面停在第3字节,现停在第9字节

1.3 模式 2 : 从文件末尾为起点,f.seek(-6, 2)从末尾往左移6字节,正数右移,负数左移

2. 三种模式适用范围:

2.1 mode="t"模式: seek只能用 模式 0, 而另一种移动read(n)中n,只有mode="t"模式下,代表字符个数

with open(r"Y:\new\a.txt", mode="rt", encoding="utf-8") as f:  # 文件内容:hello你好
    print(f.read(6))  # 打印: hello你 ,以字符为单位,中英文都是一个字符

2.2 mode="b"模式: seek都可用 模式 0, 1, 2, seek和read(n)中n都代表字节个数

with open(r"Y:\new\a.txt", mode="rb") as f:  # 文件内容:hello你好
    print(f.read(6))  # 打印: b'hello\xe4' ,以字节为单位,utf-8中,中文3字节,英文1字节
    f.seek(0, 2)  # 指针跳到末尾
    print(f.tell())  # tell获取从文件开头到当前位置的总字节数

3. 示例: 模拟写tail -f access.log

3.1 测试程序写入日志

import time

with open('access.log', mode='at', encoding='utf-8') as f:
    f.write("%s %s\n" % (time.strftime("%Y-%m-%d %H:%M:%S %p"), "程序写的日志内容"))

3.2 模拟写tail -f 查看日志

import time

with open('access.log', mode='rb') as f:
    f.seek(0, 2)
    while True:
        line = f.readline()  # readline每次读一行
        if len(line) == 0:  # 没有日志的时候, 稍微等待, 减少负载开销
            time.sleep(0.5)  # 死循环会不停调用,负载会升高
        else:
            print(line.decode('utf-8'), end='')  # 原日志中\n,打印默认也有,会有两个\n去掉一个

四. 操作文件的方法

1. f.read(n) 从当前位置读到末尾,只有mode="t"模式下,read(n)中n代表字符个数

2. f.readlines() rt模式,以行为单位读取文本,存入列表['hello你好\n','l2\n','l3']

3. f.writelines("hello") wt模式, 循环分别写入5个字母, 而f.write("hello")一次写入

with open(r"Y:\new\a.txt", mode="wt", encoding="utf-8") as f:
    lines = ["aa\n", "bb\n", "cc\n"]
    for line in lines:  # 这两行效果等于f.writelines(lines), 实质就是for循环取值
        f.write(line)

4. f.flush() 内存数据刷入硬盘

5. f.truncate(size) 截断,从开头保留n个字节,后面全删,是写操作,故要r+,a模式

with open(r"Y:\new\a.txt", mode="r+t", encoding="utf-8") as f:
    f.truncate(3)

五. 修改文件的方式

1. 方式一: 硬盘文件一次性读入内存, 内存中修改完, 再覆盖原文件,不额外占用硬盘空间, 过多占用内存

with open(r"Y:\new\a.txt", mode="rt", encoding="utf-8") as f1:
    data = f1.read()
    res = data.replace("source", "target")
with open(r"Y:\new\a.txt", mode="wt", encoding="utf-8") as f2:
    f2.write(res)

2. 方式二: 逐行读源文件,内存中修改后,逐行写入临时文件,删除源,临时文件重命名,额外占用硬盘空间, 节省内存

import os

with open(r"Y:\new\a.txt", mode="rt", encoding="utf-8") as f1, \
        open(r"Y:\new\.a.txt.swp", mode="wt", encoding="utf-8") as f2:
    for line in f1:
        f2.write(line.replace("source", "target"))

os.remove(r"Y:\new\a.txt")
os.rename(r"Y:\new\.a.txt.swp", r"Y:\new\a.txt")
上一篇 下一篇

猜你喜欢

热点阅读