当前位置: 首页 > news >正文

【Python】文件处理(一)

目录

  • 文件处理
    • 基本概念
    • 打开文件
    • 写入文件
    • 读取文件
    • 关闭文件
    • 文件指针
    • 文件缓冲
    • 重命名和删除文件
    • 移动和复制文件
    • 目录操作(文件夹管理)

文件处理

基本概念

在 Python 中,文件处理就是和计算机磁盘上的文件进行交互:

  • 打开文件(open)
  • 读取数据(read)
  • 写入数据(write)
  • 关闭文件(close)

Python 提供了内置函数 open() 来完成文件的打开操作,返回一个 文件对象,我们就可以通过这个对象进行读写。

语法:

file = open("filename", "mode")
  • "filename":文件路径,可以是相对路径(example.txt)或绝对路径(/Users/.../example.txt
  • "mode":打开文件的模式(如 r 读,w 写,a 追加,rb 二进制读等)

打开文件

在 Python 中,文件操作分为 三个阶段

  1. 打开文件(open):建立程序与文件之间的连接,返回一个文件对象(file object)。
  2. 操作文件(读写):通过文件对象的方法(如 .read().write())来读写文件内容。
  3. 关闭文件(close):断开连接,释放资源。

第一步“打开文件”就靠内置函数 open()

open() 函数语法

open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

参数详解:

参数作用
file文件路径,可以是相对路径或绝对路径,例如 "test.txt""C:/Users/me/test.txt"
mode文件打开模式(默认 'r',只读模式),详细见下一节
buffering缓冲策略: 0 = 无缓冲(只能二进制模式) 1 = 行缓冲(文本模式常用) >1 = 使用指定大小的缓冲区 -1 = 系统默认
encoding指定编码方式(常用 'utf-8',Windows 下如果不指定可能默认 'cp936'/GBK,容易乱码)
errors出现编码错误时的处理方式,比如 'ignore'(忽略)、'replace'(替换为 ?
newline控制换行符的处理(文本模式下才生效),常用于跨平台文件换行一致性
closefd如果为 False,则文件描述符不会被关闭(一般不用,特殊场景才设置)
opener高级用法,可以自定义打开逻辑(例如沙盒限制、加密文件等)

文件打开模式(mode)

模式参数最常用的是以下几种(必须理解清楚):

模式含义文件不存在时文件存在时
'r'只读模式(默认)报错从头开始读取
'w'写入模式(覆盖写)创建新文件清空原文件再写
'a'追加模式(append)创建新文件在文件末尾写入
'x'独占写模式创建新文件报错,避免覆盖
'b'二进制模式--
't'文本模式(默认)--
'+'读写模式(更新模式)--

常见组合:

  • 'rb':以二进制方式只读文件(读图片、视频、音频等)
  • 'wb':以二进制方式写文件(覆盖)
  • 'a+':追加并可读写
  • 'r+':可读写(从文件头开始,不清空内容)
  • 'w+':可读写,但会先清空文件

打开文件的基本示例

  1. 只读模式

    # 打开文件(默认就是 'r')
    f = open("example.txt", "r", encoding="utf-8")
    content = f.read()
    print(content)
    f.close()
    
  2. 写入模式(覆盖)

    f = open("example.txt", "w", encoding="utf-8")
    f.write("Hello, Python!\n")
    f.close()
    
  3. 追加模式

    f = open("example.txt", "a", encoding="utf-8")
    f.write("This line will be added.\n")
    f.close()
    
  4. 二进制模式

    f = open("image.png", "rb")
    data = f.read()
    print(len(data))  # 打印字节数
    f.close()
    

推荐用法:with 上下文管理器

好处:不用手动调用 close(),Python 会自动关闭文件,避免资源泄露。

with open("example.txt", "r", encoding="utf-8") as f:content = f.read()print(content)# 退出 with 语句块时,文件自动关闭

常见错误与注意事项

  1. 编码问题(Windows 上最常见)

    # 可能报错:UnicodeDecodeError
    f = open("test.txt", "r")  
    # 推荐:明确指定 utf-8
    f = open("test.txt", "r", encoding="utf-8")
    
  2. 模式错误

    • 文件不存在时用 'r' 打开 → FileNotFoundError
    • 'w' 打开时会清空原内容 → 小心数据丢失
    • 想读写都能用时不要忘记加 '+'
  3. 路径问题

    • Windows 下路径要么用 r"C:\Users\me\test.txt"(原始字符串)
    • 要么用斜杠 /(推荐,Python 能识别)
  4. 二进制与文本模式区别

    • 文本模式下,内容是 str
    • 二进制模式下,内容是 bytes

写入文件

文件写入指的是把程序中的数据(字符串或字节)保存到磁盘文件中。
在 Python 中,写文件通常有三步:

  1. 打开文件(用 open() 并选择写模式 w、追加模式 a、或读写模式 +)。
  2. 写入内容(常用 .write().writelines())。
  3. 关闭文件.close() 或用 with 自动关闭)。

常用写入方法

  1. write(string)

    • 将一个 字符串 写入文件。
    • 返回写入的字符数(文本模式)或字节数(二进制模式)。
    with open("example.txt", "w", encoding="utf-8") as f:count = f.write("Hello, Python!\n")print("写入了字符数:", count)  # 输出 15
    
  2. writelines(iterable)

    • 一次性写入 可迭代对象(如列表、元组)中的多个字符串。
    • 不会自动加换行符,需要自己在字符串里加 \n
    lines = ["第一行\n", "第二行\n", "第三行\n"]
    with open("example.txt", "w", encoding="utf-8") as f:f.writelines(lines)
    
  3. print(..., file=f)

    • 利用 print()file 参数写入,比 .write() 更方便(会自动换行,除非指定 end="")。
    with open("example.txt", "w", encoding="utf-8") as f:print("使用 print 写入一行", file=f)print("自动带换行", file=f)
    

文件写入模式

写入时必须选择正确的模式,否则可能导致数据丢失:

模式含义文件不存在文件存在
'w'只写模式新建文件清空原内容
'a'追加模式新建文件在文件末尾追加
'x'独占写新建文件文件已存在时报错
'w+'读写模式新建文件清空原内容
'a+'追加读写新建文件从末尾追加,但可读

小结:

  • 覆盖写'w''w+'
  • 追加写'a''a+'
  • 安全写(不想覆盖已有文件) → 'x'

代码示例

  1. 覆盖写入

    with open("example.txt", "w", encoding="utf-8") as f:f.write("这会清空旧文件并写入新内容\n")
    
  2. 追加写入

    with open("example.txt", "a", encoding="utf-8") as f:f.write("这是追加的一行\n")
    
  3. 写入多行(列表)

    lines = ["line1\n", "line2\n", "line3\n"]
    with open("example.txt", "w", encoding="utf-8") as f:f.writelines(lines)
    
  4. 二进制写入

    • 用于写图片、音频等非文本数据。
    data = b"\x48\x65\x6c\x6c\x6f"  # "Hello" 的字节形式
    with open("binary.dat", "wb") as f:f.write(data)
    
  5. 边读边写(更新模式)

    with open("example.txt", "r+", encoding="utf-8") as f:f.write("更新文件开头内容")f.seek(0)       # 移动到文件头print(f.read()) # 读出全部内容
    

常见注意事项

  1. 编码问题

    • 写入中文时建议指定 encoding="utf-8",否则可能乱码。
    with open("example.txt", "w", encoding="utf-8") as f:f.write("你好,世界\n")
    
  2. 换行符问题

    • write() 不会自动换行,需要 \n
    • print(..., file=f) 会自动加换行。
  3. 数据未立即写入磁盘

    • Python 会使用缓冲区,文件内容可能暂存在内存。
    • 解决:
      • f.flush() → 手动刷新缓冲区。
      • with open(...) → 自动关闭文件时刷新。
  4. 覆盖风险

    • 'w''w+' 会清空文件,小心数据丢失。
    • 如果只想追加,应使用 'a''a+'
  5. 写入二进制 vs 文本

    • 文本模式下 .write() 参数必须是 str
    • 二进制模式下 .write() 参数必须是 bytes

读取文件

文件读取的目标是从磁盘中获取数据到内存。
在 Python 中,读取通常步骤:

  1. 打开文件open(),模式一般是 'r''rb''r+')。
  2. 读取文件内容(用 .read().readline().readlines() 或迭代)。
  3. 关闭文件f.close()with open(...) 自动关闭)。

常见读取方法

  1. read([size])

    • 作用:读取文件中指定字节/字符数;如果不传 size,则读取整个文件。
    • 返回值:字符串(文本模式)或字节串(字节模式)。
    with open("example.txt", "r", encoding="utf-8") as f:data = f.read()      # 一次性读完整个文件print(data)with open("example.txt", "r", encoding="utf-8") as f:part = f.read(10)    # 只读前10个字符print(part)
    

    大文件时不建议一次性读完,容易占满内存,应分块读。

  2. readline([size])

    • 作用:读取文件中的一行(包含换行符 \n),读到末尾返回空字符串。
    • 参数 size:可选,表示最多读多少字符,不一定能读完整一行。
    with open("example.txt", "r", encoding="utf-8") as f:line1 = f.readline()print("第一行:", line1)line2 = f.readline()print("第二行:", line2)
    
  3. readlines()

    • 作用:一次性读取所有行,返回一个 列表,每行作为一个字符串元素。
    with open("example.txt", "r", encoding="utf-8") as f:lines = f.readlines()print(lines)  # ["第一行\n", "第二行\n", "第三行\n"]
    

    注意:大文件慎用,会把所有行都读入内存。

  4. 直接迭代文件对象

    • 文件对象本身就是可迭代的,可以一行一行读取,更节省内存
    with open("example.txt", "r", encoding="utf-8") as f:for line in f:print("读取到:", line.strip())
    

    推荐大多数情况下用这种方式。

高级读取技巧

  1. 分块读取(适合大文件)

    with open("bigfile.txt", "r", encoding="utf-8") as f:while True:chunk = f.read(1024)  # 每次读 1024 字符if not chunk:breakprint(chunk, end="")
    
  2. 随机访问文件内容

    • seek(offset, whence):移动文件指针。
      • whence=0:从开头算(默认)。
      • whence=1:从当前位置算。
      • whence=2:从文件末尾算。
    • tell():返回当前位置。
    with open("example.txt", "r", encoding="utf-8") as f:f.seek(5)         # 移动到第 5 个字符print(f.read(10)) # 读取10个字符print("当前位置:", f.tell())
    
  3. 二进制读取

    用于图片、音频、视频等非文本文件:

    with open("image.png", "rb") as f:data = f.read(20)   # 读取前20字节print(data)         # b'\x89PNG\r\n\x1a\n...'
    
  4. readinto(buffer)

    • 直接读取数据到现有的 字节数组,避免创建新对象(效率更高)。
    import array
    buf = array.array('b', b'\0' * 10)
    with open("example.txt", "rb") as f:f.readinto(buf)
    print(buf)
    
  5. 内存映射(大文件优化)

    • 使用 mmap 可以把文件映射到内存,像操作字节数组一样读写,非常高效。
    import mmapwith open("example.txt", "r+b") as f:mm = mmap.mmap(f.fileno(), 0)print(mm[:10])   # 前10个字节mm.close()
    

注意事项与常见问题

  1. 编码问题
    • 默认编码可能不同(Windows 常见 gbk),建议总是加 encoding="utf-8"
    • 否则可能 UnicodeDecodeError
  2. 换行符差异
    • Windows:\r\n
    • Linux / Mac:\n
    • Python 会自动统一为 \n,除非 newline 参数另设。
  3. 大文件内存占用
    • 避免用 .read().readlines() 一次性读入。
    • 推荐用 迭代分块读取
  4. 二进制 vs 文本
    • 文本模式返回 str
    • 二进制模式返回 bytes
  5. 文件未关闭
    • with open(...) 自动关闭,避免资源泄漏。

关闭文件

为什么要关闭文件?

当我们用 open() 打开一个文件时,操作系统会给程序分配一个 文件描述符(file descriptor),这是系统级别的资源。

如果不关闭文件,可能会导致:

  1. 资源泄漏:打开太多文件却没关闭,系统会报错:OSError: [Errno 24] Too many open files
  2. 数据丢失:写入数据时,内容会先存到 缓冲区,如果不关闭或 flush(),数据可能没写入磁盘。
  3. 文件锁未释放:某些系统下文件可能被锁定,导致其他程序不能访问。

所以,关闭文件是文件操作必不可少的一步

close() 方法

最基本的关闭方式是手动调用:

f = open("example.txt", "w", encoding="utf-8")
f.write("Hello, world!\n")
f.close()  # 关闭文件,释放资源

检查文件是否关闭

f = open("example.txt", "r", encoding="utf-8")
print(f.closed)  # False
f.close()
print(f.closed)  # True

.closed 属性可以判断文件是否已经关闭。

with 上下文管理器

Python 推荐使用 with 语句,它会在代码块执行完后自动调用 close(),即使发生异常也会关闭文件。

with open("example.txt", "w", encoding="utf-8") as f:f.write("这行文字会自动保存\n")# 不需要手动 f.close()

等价写法

下面两种写法效果相同:

# 传统写法
f = open("example.txt", "w", encoding="utf-8")
try:f.write("Hello\n")
finally:f.close()# with 写法(简洁、安全)
with open("example.txt", "w", encoding="utf-8") as f:f.write("Hello\n")

with 的底层原理——上下文管理协议

任何对象只要实现了 __enter__()__exit__() 方法,就满足「上下文管理协议」,可以被 with 语句使用。这两个方法的作用如下:

  1. __enter__() 方法

    • 调用时机:进入 with 代码块时自动调用。

    • 作用:通常用于「准备资源」(如打开文件、建立数据库连接、获取锁等)。

    • 返回值:会被 with ... as 变量 中的「变量」接收(可以是对象本身,也可以是其他资源对象)。

  2. __exit__() 方法

    • 调用时机:退出 with 代码块时自动调用(无论代码块内是否发生异常,一定会执行)。

    • 作用:通常用于「清理资源」(如关闭文件、断开数据库连接、释放锁等)。

      • 参数:接收三个与异常相关的参数(如果代码块内无异常,这三个参数均为 None):
        • exc_type:异常类型(如 ValueError)。
        • exc_value:异常实例(具体错误信息)。
        • traceback:异常的追踪信息。
    • 返回值:如果返回 True,则会「抑制异常」(异常不会向外传播);如果返回 False 或不返回,则异常会正常抛出。

with 语句的执行流程

结合一个实例来看 with 的完整执行步骤:

class Demo:def __enter__(self):print("进入 with 块:准备资源")return self  # 返回值会被 as 后的变量接收def __exit__(self, exc_type, exc_value, traceback):print("退出 with 块:清理资源")# 若返回 True,则抑制异常return False# 执行 with 语句
with Demo() as d:print("执行 with 块内的逻辑")# 假设这里可能发生异常# raise ValueError("故意抛出一个异常")

执行流程拆解:

  1. 创建 Demo 实例(Demo())。
  2. 自动调用实例的 __enter__() 方法,打印「进入 with 块:准备资源」,并将返回值(self)赋值给 d(即 d 就是 Demo 实例)。
  3. 执行 with 块内的代码:打印「执行 with 块内的逻辑」。
  4. 退出 with 块时,自动调用 __exit__() 方法,打印「退出 with 块:清理资源」。

即使块内发生异常(比如取消注释 raise 语句),__exit__() 依然会执行,确保资源被清理。

文件对象正是实现了这套机制,所以 with open(...) as f: 才能自动关闭。

注意事项

  1. 重复关闭文件

    • .close() 调用多次不会报错,Python 会忽略。
    f = open("example.txt", "r")
    f.close()
    f.close()  # 没问题
    
  2. 关闭后的操作

    • 如果对已经关闭的文件进行读写操作,会报 ValueError: I/O operation on closed file
    f = open("example.txt", "r")
    f.close()
    f.read()  # 报错
    
  3. flush vs close

    • f.flush():只是把缓冲区数据写入磁盘,但文件依然处于打开状态。
    • f.close():会先 flush,再释放资源。
  4. with 的多文件写法

    with open("file1.txt", "r") as f1, open("file2.txt", "w") as f2:for line in f1:f2.write(line)
    

文件指针

什么是文件指针?

文件指针是操作系统为每个打开的文件维护的 当前位置标记,它表示下一次读或写操作从文件的哪一位置开始。

  • 当你打开一个文件时,文件指针默认位置:
    • 'r''r+''w+' → 默认在 开头
    • 'a''a+' → 默认在 末尾
  • 读写文件时,文件指针会随操作移动:
    • 读操作 → 文件指针向前移动已读取的字节数
    • 写操作 → 文件指针向前移动已写入的字节数

文件指针方法

  1. tell()

    返回当前文件指针位置(以字节为单位)

    with open("example.txt", "r", encoding="utf-8") as f:print(f.tell())  # 0f.read(5)print(f.tell())  # 读取 5 个字符后指针位置变为 5(如果是 UTF-8 多字节可能略有差异)
    
  2. seek(offset, whence=0)

    移动文件指针到指定位置:

    • offset:偏移量(单位:字节)
    • whence(起点,默认 0):
      • 0:文件开头
      • 1:当前位置
      • 2:文件末尾

    示例:

    with open("example.txt", "r", encoding="utf-8") as f:f.seek(5)  # 从开头向后移动 5 个字节print(f.read(5))f.seek(0)  # 回到开头print(f.read(5))f.seek(-5, 2)  # 从文件末尾向前 5 个字节print(f.read())
    

    注意:在文本模式下 ('r''w') 偏移量是以字符为单位,如果涉及多字节字符(如中文 UTF-8),seek 有可能出现偏差。
    推荐文本文件用 'utf-8' 编码读写,如果需要精确字节控制可用二进制模式 'rb''wb'

文件指针在读写中的应用

  1. 读文件的随机访问

    with open("example.txt", "r", encoding="utf-8") as f:f.seek(10)  # 跳过前 10 个字符content = f.read(20)  # 读取 20 个字符print(content)
    
  2. 写文件的随机插入(覆盖)

    with open("example.txt", "r+", encoding="utf-8") as f:f.seek(5)f.write("INSERT")  # 会从第 5 个字符开始覆盖原文件内容
    
  3. 追加文件内容

    with open("example.txt", "a", encoding="utf-8") as f:f.write("\n追加内容")
    

    注意:追加模式下,文件指针会自动移动到文件末尾,seek 修改位置可能不会生效(取决于操作系统实现)。

为什么文本模式下 seek() 容易出问题?

  1. UTF-8/UTF-16 等编码的多字节特性
    • 英文字母通常占 1 个字节
    • 中文、日文、韩文等常占 3 个字节(UTF-8)或 2 个字节(UTF-16)
    • seek(n) 只移动 字节,而不是 字符
    • 如果偏移量落在一个字符的中间,就会导致 read() 出现乱码或 UnicodeDecodeError
  2. Python 的文本模式解码机制
    • "r" 模式下,Python 会自动解码字节 → 字符
    • 如果字节流被切割,解码器无法识别完整字符

安全策略

  1. 使用二进制模式 (rb/wb)

    如果需要精确的字节控制,先在二进制模式下用 seek() 定位,再手动解码:

    with open("test.txt", "rb") as f:f.seek(6)  # 跳过前 6 个字节data = f.read(6)  # 读取 6 个字节print(data.decode("utf-8", errors="ignore"))
    

    优点:精确控制字节偏移
    缺点:需要自己处理编码

  2. 通过字符计数定位

    先按 字符 读取,再用 len(encode) 计算对应的字节数,然后再 seek()

    text = "你好Python"
    # 想跳到第3个字符(P)
    prefix = text[:2]  # 前两个字符 "你好"
    byte_offset = len(prefix.encode("utf-8"))with open("test.txt", "rb") as f:f.seek(byte_offset)print(f.read().decode("utf-8"))  # 输出 "Python"
    

    思路:把字符串切片转成字节长度,保证不会切到字符中间

  3. 逐行读取 + 内存切片

    如果只需要定位某一行里的某个字符,可以用字符串切片代替 seek()

    with open("test.txt", "r", encoding="utf-8") as f:line = f.readline()  # 读取一行print(line[2:])      # 从第3个字符开始
    

    适合逐行处理,不依赖文件指针字节位置

  4. 借助 io 模块的 TextIOWrapper

    TextIOWrapper 提供了 按字符缓冲 的文件流,可以在二进制和文本模式之间切换:

    import iowith open("test.txt", "rb") as raw:f = io.TextIOWrapper(raw, encoding="utf-8")f.seek(0, 0)     # 移动到底层二进制流的位置print(f.read())  # 自动解码
    

    适合需要在 字节级定位字符级读取 之间切换的场景

底层原理

  1. 文件在操作系统层面由 文件描述符 表示。
  2. 文件指针是操作系统维护的一个偏移量,用来标记下一次读写的位置。
  3. Python 的 file 对象封装了这个文件描述符,并提供 .seek().tell() 方法来操作。
  4. 文件读写实际上是:
    • read() → 从指针位置读取指定字节 → 指针向后移动
    • write() → 从指针位置写入数据 → 指针向后移动

注意事项

  1. 文本模式 vs 二进制模式
    • 文本模式 ('r''w'):seek/tell 以字符为单位,多字节字符可能有偏差
    • 二进制模式 ('rb''wb'):seek/tell 精确到字节,适合文件偏移计算
  2. 追加模式的限制
    • 'a' / 'a+' 模式写入总是追加到末尾,seek 可能不能改变写入位置
  3. 与缓冲区的关系
    • 文件指针指向的位置是 Python 内存缓冲区的位置,而不是硬盘位置
    • flush()close() 会将缓冲区内容写入硬盘

文件缓冲

什么是缓冲区?

当你用 Python 打开文件进行读写时,数据不会直接“一次一字节”与硬盘交互,而是先进入内存中的一个临时区域,这个区域就是 缓冲区(buffer)

  • 目的:减少与磁盘频繁交互,提高性能
  • 工作原理
    • 写文件时:数据先写入缓冲区,等缓冲区满了或文件关闭时,再一次性写入磁盘
    • 读文件时:一次性从磁盘读取一块内容到缓冲区,程序按需从缓冲区获取

缓冲区的多层结构

当我们在 Python 里 open() 一个文件时,实际涉及 三层缓冲

  1. 操作系统缓冲(Page Cache)
    • 所有磁盘 I/O 操作首先会经过 OS 缓存(内核页缓存)。
    • 程序写入的数据 → 进入 OS 缓存 → 系统稍后再写入硬盘。
  2. C 标准库缓冲(stdio 层)
    • Python 内部调用 C 标准库的 fopenfwrite 等,这一层也有缓冲。
    • 决定了 buffering 参数的行为(行缓冲 / 全缓冲 / 无缓冲)。
  3. Python 层缓冲(io 模块)
    • Python io.TextIOWrapper(文本模式)和 io.BufferedWriter(二进制模式)再维护一层缓冲。
    • 例如:f.write("abc") 并不会马上写盘,而是写到 Python 的缓冲对象里。

结论:写入磁盘并不是立刻发生的,而是可能停留在 Python → C stdio → OS 页缓存 的任意一层。

Python 文件缓冲机制

open(file, mode, buffering, ...) 中,buffering 参数决定缓冲方式:

buffering 值行为
0无缓冲(只允许二进制模式)。读写直接操作系统调用,效率低,但实时性强
1行缓冲(仅文本模式)。遇到换行符 \n 或调用 flush()/close() 时写入磁盘
>1使用指定大小的 固定缓冲区(单位:字节)
默认文本模式下 → 行缓冲;二进制模式下 → 固定缓冲区(通常 4KB 或 8KB,依操作系统而定)

flush() 的作用

  • flush() 会把 Python 层缓冲C stdio 缓冲 的数据推送到 操作系统缓冲
  • 但它不能保证数据立刻写入物理磁盘。

示例:

with open("log.txt", "w", encoding="utf-8") as f:f.write("第一条日志\n")f.flush()  # 此时数据进入 OS 缓冲,但可能还没写到磁盘

os.fsync() 的作用

如果你要确保数据真正落到磁盘(防止断电丢失),需要调用 系统调用 fsync()

import oswith open("log.txt", "w", encoding="utf-8") as f:f.write("关键日志\n")f.flush()             # 刷到操作系统缓存os.fsync(f.fileno())  # 强制 OS 把缓存写入硬盘

注意:

  • fsync()flush() 慢得多(需要物理磁盘操作)。
  • 用在关键场景(数据库写 WAL、金融交易日志),而不是每次写入。

自动刷新机制

Python 有几种方式可以实现“写了就刷新”:

  1. 行缓冲(buffering=1

    • 仅文本模式有效。
    • 每次写入 换行符 \n 时,缓冲区会自动刷新。
    f = open("log.txt", "w", buffering=1, encoding="utf-8")
    f.write("这一行会立即写入\n")  # 遇到换行 -> 自动 flush
    
  2. print(..., flush=True)

    Python 的 print 内置参数 flush=True 可以强制刷新:

    print("即时日志", file=open("log.txt", "w"), flush=True)
    
  3. 无缓冲(buffering=0

    • 只允许二进制模式 ("wb""rb")。
    • 每次写操作都会直接调用系统写入,实时性最高,性能最差。
    f = open("raw.bin", "wb", buffering=0)
    f.write(b"data")  # 立即写入磁盘
    

写入效率优化

  1. 批量写入 vs 逐条写入

    • 低效:

      with open("data.txt", "w", encoding="utf-8") as f:for i in range(1000000):f.write(f"{i}\n")  # 每次写入都可能触发缓冲处理
      
    • 高效:

      with open("data.txt", "w", encoding="utf-8") as f:lines = [f"{i}\n" for i in range(1000000)]f.writelines(lines)  # 一次性写入
      
  2. 调整缓冲区大小

    f = open("bigfile.txt", "wb", buffering=1024*1024)  # 1MB 缓冲区
    

    大文件 I/O 时减少磁盘调用次数,性能显著提升。

  3. 避免频繁 flush/fsync

    • flush()/fsync() 都会打断批量写入的优化,过于频繁会拖慢性能。

    • 最佳实践:批量写入 → 定时 flush → 关键数据点 fsync

并发与缓冲

在多进程/多线程环境中:

  • 缓冲会导致写入顺序不一致,因为每个进程有独立缓冲。
  • 如果多个进程同时写文件,可能发生覆盖或交错。

解决方法:

  1. 使用 O_APPEND 模式(在 Linux 下保证原子追加)。
  2. 使用 文件锁fcntlportalocker)。
  3. 对日志类写入,推荐:一进程写,其他进程用队列传数据

重命名和删除文件

文件重命名(Renaming Files)

在 Python 中,主要通过 os 模块 提供的 os.rename()os.replace() 来重命名文件。

  1. os.rename(src, dst)

    • 作用:把文件(或目录)从 src 路径重命名为 dst 路径。

    • 语法

      os.rename(src, dst)
      
      • src:原文件路径(字符串)
      • dst:目标文件路径(字符串)
    • 特点

      • 如果 dst 已经存在,Windows 上会报错,Linux 上会覆盖(取决于系统)。
      • srcdst 可以在 同一个目录下(单纯改名字),也可以是 不同目录(相当于移动文件)。
    • 示例

      import os# 假设当前目录下有 old.txt 文件
      os.rename("old.txt", "new.txt")  # 将 old.txt 重命名为 new.txt
      print("重命名完成!")
      
  2. os.replace(src, dst)

    • 作用:与 os.rename() 类似,但更安全,即使目标文件存在也会强制覆盖

    • 语法

      os.replace(src, dst)
      
    • 示例

      import os# 即使 new.txt 已经存在,也会被覆盖
      os.replace("temp.txt", "new.txt")
      
    • 区别总结

      方法目标文件存在时的行为适用场景
      os.rename()Windows 上报错,Linux 上可能覆盖普通重命名
      os.replace()强制覆盖确定要替换旧文件时
  3. 使用 pathlib.Path.rename()

    • Python3 推荐的 面向对象写法

      from pathlib import Pathp = Path("old.txt")
      p.rename("new.txt")   # 等价于 os.rename()
      

注意事项

  1. 路径正确性
    • 如果文件不在当前目录,需要写绝对路径或相对路径。
    • 推荐使用 os.path.join()Path 来拼接路径。
  2. 权限问题
    • 如果文件被占用(Windows)或没有权限,会抛出 PermissionError
  3. 跨磁盘/分区限制
    • 有些系统 rename 不能跨分区移动文件,需改用 shutil.move()

文件删除(Deleting Files)

在 Python 中,可以通过 os.remove()os.unlink()Path.unlink() 删除文件。

  1. os.remove(path)

    • 作用:删除指定路径下的文件。

    • 语法

      os.remove(path)
      
    • 示例

      import osos.remove("new.txt")  # 删除文件
      print("删除完成!")
      
  2. os.unlink(path)

    • 作用os.unlink()os.remove() 的别名,两者完全一样。

    • 语法

      os.unlink(path)
      
    • 使用场景:通常 Linux/Unix 系统里更习惯使用 unlink,表示从文件系统的目录树中“解除链接”。

  3. 使用 pathlib.Path.unlink()

    • 面向对象方式

      from pathlib import Pathp = Path("example.txt")
      if p.exists():p.unlink()   # 删除文件print("删除成功!")
      

删除目录与文件的区别

  • 删除文件os.remove() / os.unlink() / Path.unlink()
  • 删除空目录os.rmdir() / Path.rmdir()
  • 删除非空目录shutil.rmtree(path)(递归删除整个文件夹)

常见错误与解决方法

  1. FileNotFoundError

    • 当指定的文件不存在时会报错。
    • 解决方法:在删除前加 os.path.exists(path)Path.exists() 检查。
    if os.path.exists("old.txt"):os.remove("old.txt")
    else:print("文件不存在!")
    
  2. PermissionError

    • 文件正在被占用(Windows 常见,比如文件在记事本中打开)。
    • 解决方法:关闭占用文件的程序,或在 Linux 上使用 sudo
  3. IsADirectoryError

    • 如果用 os.remove() 删除目录,会报错。
    • 解决方法:用 os.rmdir()shutil.rmtree() 删除目录。

移动和复制文件

文件移动(Moving Files)

在 Python 中,文件移动操作常用 shutil.move()

shutil.move(src, dst)

  • 作用:把文件或目录从 src 移动到 dst

  • 语法

    import shutilshutil.move(src, dst)
    
  • 参数说明

    • src:源文件或目录路径
    • dst:目标路径(可以是目录,也可以是新文件名)
  • 特点

    • 如果 dst 是目录 → 文件被移动到该目录下,保留原名称。
    • 如果 dst 是文件名 → 文件会被移动并重命名。
    • 如果 dst 存在同名文件 → 会覆盖。

移动文件示例

import shutil# 将 data.txt 移动到 backup 目录下
shutil.move("data.txt", "backup/")# 将 log.txt 移动并重命名为 log_old.txt
shutil.move("log.txt", "backup/log_old.txt")

移动目录

import shutil# 移动整个文件夹
shutil.move("my_folder", "archive/")

os.rename() 的区别

  • os.rename():只能在同一磁盘/分区下移动,跨分区会报错。
  • shutil.move():支持跨分区,会自动处理。
    一般推荐用 shutil.move(),更通用。

os.rename() 的区别

  • os.rename():只能在同一磁盘/分区下移动,跨分区会报错。
  • shutil.move():支持跨分区,会自动处理。
    一般推荐用 shutil.move(),更通用。

文件复制(Copying Files)

复制文件主要用 shutil 模块 的几个方法,不同方法保留的信息不同。

  1. shutil.copy(src, dst)

    • 作用:复制文件内容到新路径。

    • 特点

      • 只复制文件内容和权限(mode),不复制元数据(如创建时间、修改时间等)。
      • 如果 dst 是目录 → 保持原文件名。
    • 示例

      import shutil# 将 data.txt 复制到 backup/ 目录下
      shutil.copy("data.txt", "backup/")# 将 log.txt 复制并重命名
      shutil.copy("log.txt", "backup/log_copy.txt")
      
  2. shutil.copy(src, dst)

    • 作用:复制文件内容到新路径。

    • 特点

      • 只复制文件内容和权限(mode),不复制元数据(如创建时间、修改时间等)。
      • 如果 dst 是目录 → 保持原文件名。
    • 示例

      import shutil# 将 data.txt 复制到 backup/ 目录下
      shutil.copy("data.txt", "backup/")# 将 log.txt 复制并重命名
      shutil.copy("log.txt", "backup/log_copy.txt")
      
  3. shutil.copy2(src, dst)

    • 作用:在 copy 的基础上,尽可能保留文件的元数据(修改时间、访问时间等)。

    • 推荐:如果要保留完整文件信息,最好用 copy2

    • 示例

      import shutilshutil.copy2("data.txt", "backup/")
      

方法对比

方法是否保留权限是否保留元数据(时间戳等)dst 可以是目录?
shutil.copyfile
shutil.copy
shutil.copy2

一般用 copy2,除非你只想要文件内容。

目录复制

如果需要复制整个目录,使用 shutil.copytree()

shutil.copytree(src, dst, dirs_exist_ok=False)

  • 作用:递归复制整个目录树(目录及其内容)。

  • 语法

    shutil.copytree(src, dst, dirs_exist_ok=False)
    
  • 参数说明

    • src:源目录
    • dst:目标目录(必须不存在,除非 dirs_exist_ok=True
    • dirs_exist_ok=True:允许复制到已存在的目录(Python 3.8+)。
  • 示例

    import shutil# 将 my_folder 整个复制到 backup/my_folder
    shutil.copytree("my_folder", "backup/my_folder")# 覆盖到已存在目录(Python 3.8+)
    shutil.copytree("my_folder", "backup/my_folder", dirs_exist_ok=True)
    

总结表

操作方法说明
移动文件/目录shutil.move(src, dst)支持跨分区,覆盖同名文件
复制文件(仅内容)shutil.copyfile(src, dst)不保留权限/元数据
复制文件(含权限)shutil.copy(src, dst)保留权限,不保留时间戳
复制文件(完整)shutil.copy2(src, dst)保留权限 + 元数据
复制目录shutil.copytree(src, dst)递归复制整个目录

目录操作(文件夹管理)

获取和切换工作目录

  1. 获取当前工作目录

    • os.getcwd()

      import osprint(os.getcwd())  # 输出当前脚本运行所在的目录
      
    • Path.cwd()(推荐写法)

      from pathlib import Pathprint(Path.cwd())  # Path 对象,支持链式操作
      
  2. 切换工作目录

    • os.chdir(path)

      import osos.chdir("/Users/username/Documents")
      print(os.getcwd())  # 切换后的路径
      

    注意:切换目录后,后续所有相对路径操作都会基于新的工作目录。

创建目录

  1. 创建单级目录

    • os.mkdir(path)

      import osos.mkdir("new_folder")  # 在当前目录下新建文件夹
      
    • Path.mkdir()

      from pathlib import PathPath("new_folder").mkdir()
      
  2. 创建多级目录

    • os.makedirs(path)

      import osos.makedirs("a/b/c")  # 递归创建 a/b/c 目录
      
    • Path.mkdir(parents=True)

      from pathlib import PathPath("a/b/c").mkdir(parents=True, exist_ok=True)
      
    • 参数说明:

      • parents=True:允许递归创建父目录
      • exist_ok=True:目录存在时不报错(默认会报 FileExistsError)

删除目录

  1. 删除空目录

    • os.rmdir(path)

      import osos.rmdir("new_folder")  # 只能删除空目录
      
    • Path.rmdir()

      from pathlib import PathPath("new_folder").rmdir()
      
  2. 删除非空目录

    • shutil.rmtree(path)

      import shutilshutil.rmtree("a")  # 删除整个目录树(a 及其子目录和文件)
      

    危险操作:rmtree 会递归删除所有内容,请谨慎使用。

遍历目录

  1. os.listdir(path)

    import osfiles = os.listdir(".")  # 当前目录
    print(files)
    

    输出是一个列表,包含文件和目录名称。

  2. os.scandir(path)(效率更高)

    import oswith os.scandir(".") as entries:for entry in entries:print(entry.name, "是目录吗?", entry.is_dir())
    

    返回 DirEntry 对象,比 listdir() 更快,可以直接判断文件类型。

  3. Path.iterdir()(推荐)

    from pathlib import Pathfor item in Path(".").iterdir():if item.is_file():print("文件:", item.name)elif item.is_dir():print("目录:", item.name)
    

路径拼接与处理

  1. os.path 方式

    import ospath = os.path.join("folder", "file.txt")  # 拼接路径
    print(path)print(os.path.basename(path))  # file.txt
    print(os.path.dirname(path))   # folder
    print(os.path.splitext(path))  # ('folder/file', '.txt')
    print(os.path.abspath("file.txt"))  # 转为绝对路径
    
  2. pathlib 方式(更现代)

    from pathlib import Pathp = Path("folder") / "file.txt"  # 用 / 拼接路径
    print(p)print(p.name)      # file.txt
    print(p.parent)    # folder
    print(p.suffix)    # .txt
    print(p.stem)      # file
    print(p.resolve()) # 绝对路径
    

目录操作常见应用场景

  1. 批量处理文件

    from pathlib import Pathfor file in Path("logs").glob("*.txt"):print("处理文件:", file)
    
  2. 按日期创建日志目录

    from pathlib import Path
    import datetimetoday = datetime.date.today().isoformat()
    Path(f"logs/{today}").mkdir(parents=True, exist_ok=True)
    
  3. 递归遍历所有文件

    from pathlib import Pathfor file in Path("project").rglob("*.py"):print(file)
    
http://www.dtcms.com/a/406923.html

相关文章:

  • win10怎么做网站wordpress wooyun
  • 织梦网站登录网上做网站赚钱吗
  • Linux数据安全与备份策略完全指南
  • 哈尔滨网站建设服务公司暴雪游戏服务中心
  • wordpress 关闭评论网站优化排名提升
  • 硅基计划5.0 MySQL 壹 初识MySQL 初版
  • Linux之挂载新的硬盘(超详细!)
  • 部署 GitLab 服务器
  • C++项目:仿muduo库高并发服务器-------connection模块
  • 网站建设需要的资质互联网保险的发展现状
  • 8-机器学习与大模型开发数学教程-第0章 预备知识-0-8 编程与数值计算基础(浮点数精度、溢出、数值稳定性)
  • php网站开发书微信公众号手机网站开发
  • 做网站需要工商执照吗代人做网站
  • Go基础:模块化管理为什么能够提升研发效能?
  • 合肥专业做网站公司wd wordpress
  • IR 680LT Maleimide,IR 680LT马来酰亚胺用于蛋白质标记与定量分析
  • 打工人日报#20250925
  • Kubernetes Pod 的生命周期与故障排查
  • Java List列表创建方法大总结
  • 河南工信建设网站市场营销师报名官网
  • 没有文字的网站怎么优化建立旅游网站的目的
  • Spring Boot用户登录注册系统设计与实现
  • 筑牢AI安全防线:阿里云AI安全护栏
  • seo网站优化教程如何把自己电脑做网站服务器吗
  • 网站的内容建设安徽招标投标信息网
  • Qt中,​Latin-1​字符编码简介
  • 现有项目迁移到新的仓库中
  • 金融网站建设方案ppt模板亚马逊关键词搜索器
  • 分布式之抢购
  • Music Tag Web 怎么安装 ffmpeg?