You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python fileinput遇异常时如何保持原文件内容不变?

问题:fileinput原地替换触发UnicodeDecodeError导致原文件被清空,如何保留原文件?

我用Python 3的fileinput模块做文件原地文本替换,部分非可读/二进制文件会触发UnicodeDecodeError,异常发生时原文件内容会被清空——原文件内容会被移至.bak文件,但异常后.bak文件被删除且没恢复到原文件。我没法提前预判所有触发异常的文件类型,没法用if语句排除这些文件,请问怎么在异常发生时不对文件做任何操作,保持原文件内容不变?

原代码示例:

for subdir, dirs, files in os.walk(currWorkingDir):
    for file in files:
        try:
            for line in fileinput.input(os.path.join(subdir, file), inplace=True, encoding='utf-8'):
                line = line.replace('XXX', 'x')
                print(line, end='')
        except UnicodeDecodeError as e:
            sys.stderr.write('binary file and should not be modified {}.\n'.format(
                os.path.join(subdir, file)))
            fileinput.close()
解决方案

核心问题是fileinput开启inplace=True后,会先把原文件重命名为.bak,再创建新的同名文件写入内容。一旦解码失败抛出异常,程序中断时新文件是空的,且默认情况下.bak会被自动清理,导致原文件丢失。下面提供两种可行方案:

方案1:预校验文件编码,提前跳过无法解码的文件

在执行替换操作前,先尝试用指定编码读取文件(只读前几行即可,提升效率),确认能正常解码后再进入fileinput流程,否则直接跳过。

修改后的代码:

import os
import sys
import fileinput

currWorkingDir = "./your_target_dir"  # 替换为你的目标目录

for subdir, dirs, files in os.walk(currWorkingDir):
    for file in files:
        file_path = os.path.join(subdir, file)
        # 预校验文件是否能以utf-8解码
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                # 只读前10行做校验,避免读取大文件耗时
                for _ in range(10):
                    next(f)
        except UnicodeDecodeError:
            sys.stderr.write(f"二进制文件,跳过修改:{file_path}\n")
            continue
        # 校验通过,执行替换
        try:
            for line in fileinput.input(file_path, inplace=True, encoding='utf-8'):
                line = line.replace('XXX', 'x')
                print(line, end='')
        except Exception as e:
            sys.stderr.write(f"处理文件出错:{file_path},错误信息:{str(e)}\n")

方案2:捕获异常后手动恢复备份文件

如果必须在fileinput执行过程中处理异常,可以指定backup参数保留备份文件,一旦触发异常,就把备份文件恢复回原文件。

修改后的代码:

import os
import sys
import fileinput
import shutil

currWorkingDir = "./your_target_dir"  # 替换为你的目标目录

for subdir, dirs, files in os.walk(currWorkingDir):
    for file in files:
        file_path = os.path.join(subdir, file)
        backup_path = f"{file_path}.bak"
        try:
            # 指定backup参数,强制保留备份文件
            for line in fileinput.input(file_path, inplace=True, encoding='utf-8', backup='.bak'):
                line = line.replace('XXX', 'x')
                print(line, end='')
            # 处理成功后删除备份文件(可选操作)
            if os.path.exists(backup_path):
                os.remove(backup_path)
        except UnicodeDecodeError:
            sys.stderr.write(f"二进制文件,恢复原文件:{file_path}\n")
            # 将备份文件恢复为原文件
            if os.path.exists(backup_path):
                shutil.move(backup_path, file_path)
        except Exception as e:
            sys.stderr.write(f"处理文件出错,恢复原文件:{file_path},错误信息:{str(e)}\n")
            if os.path.exists(backup_path):
                shutil.move(backup_path, file_path)

注意点

  • 方案1效率更高,能提前过滤掉大部分无法解码的文件,避免进入修改流程;
  • 方案2的backup参数会强制生成备份文件,处理成功后记得手动删除(如果不需要保留的话);
  • 极端情况下,文件前几行是文本但后续是二进制,方案1可能漏判,此时可以结合两种方案,在fileinput循环内也捕获异常并恢复备份。

内容的提问来源于stack exchange,提问作者John Wicked

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 08:33:34