Python 读写文本文件时如何处理编码、空行与内容筛选

AI智能摘要
文本脚本出错,未必是读写语句本身,编码不匹配、空行混杂和一次性加载大文件都可能带来乱码、内存压力或错误结果。文章详解如何用上下文管理器与 UTF-8 编码安全读写,逐行处理文件,并区分 strip() 与 rstrip("rn"),结合关键词筛选生成清洗后的文本;面对不同清洗需求,怎样选择合适的处理方式?
— 此摘要由AI分析文章内容生成,仅供参考。

处理文本文件时,脚本能否正常运行,往往不只取决于读取和写入语句,还取决于编码是否匹配、空行是否处理得当,以及文件是否被一次性加载到内存。对于日志、配置片段或普通文本,使用上下文管理器逐行读取,通常更稳妥。

打开文本文件时先确定编码

Python 的 open() 函数可以通过 encoding 参数指定文本编码。现在常见的文本文件通常使用 UTF-8,因此可以明确写出:

with open("input.txt", "r", encoding="utf-8") as file:
    content = file.read()

这里的 "r" 表示以读取模式打开文件。with 代码块结束后,文件会自动关闭,不需要再调用 close()。

写入文件时同样要指定编码:

with open("output.txt", "w", encoding="utf-8") as file:
    file.write("第一行内容n")
    file.write("第二行内容n")

"w" 会创建文件;如果文件已经存在,原有内容会被覆盖。如果希望保留原内容并在末尾追加,应使用 "a":

with open("output.txt", "a", encoding="utf-8") as file:
    file.write("追加的一行内容n")

如果打开文件时报编码错误,通常说明实际文件编码与代码中的设置不一致。此时应先确认文件的保存编码,再修改 encoding 参数。不能为了让程序继续运行就盲目忽略错误,否则可能得到乱码或损坏的文本。某些带有编码标记的 UTF-8 文件可以尝试使用 utf-8-sig:

with open("input.txt", "r", encoding="utf-8-sig") as file:
    content = file.read()

逐行读取,避免一次性加载文件

read() 会把整个文件读取成一个字符串。文件较小时这种方式很直观,但如果文件内容较多,一次性读取会占用较多内存。

更适合文本清洗的写法是直接遍历文件对象:

with open("input.txt", "r", encoding="utf-8") as file:
    for line in file:
        print(line)

这里的 line 通常已经包含原文件中的换行符。如果直接使用 print(line),可能看到每行之间多出一行空白,因为 print() 自己也会添加换行。可以使用 end="" 保留原来的换行方式:

with open("input.txt", "r", encoding="utf-8") as file:
    for line in file:
        print(line, end="")

逐行遍历的好处是,程序处理完一行后就可以继续处理下一行,不需要先把整个文件保存到列表中。

判断和处理空行

清理文本时,空行可能表现为几种形式:

  • 完全没有内容的行;
  • 只包含换行符的行;
  • 只包含空格或制表符的行。

使用 line.strip() 可以去除字符串两端的空白字符,再判断结果是否为空:

if line.strip() == "":
    continue

这段代码表示:如果当前行去掉空白后没有内容,就跳过这一行。

如果只是想去掉行尾的换行符,而不希望删除行首或行尾的普通空格,可以使用:

clean_line = line.rstrip("rn")

这比 strip() 更适合需要保留原始缩进或空格的文本。两者用途不同:

line.strip()       # 判断一行是否只有空白,或同时清理两端空白
line.rstrip("rn")  # 只去掉行尾换行符

按条件筛选内容并写入新文件

下面的脚本会完成几个常见任务:

  1. 读取 input.txt;
  2. 跳过空行;
  3. 跳过包含指定关键词的行;
  4. 去掉每行末尾的换行符;
  5. 将筛选后的内容写入 cleaned.txt;
  6. 全程采用逐行处理,不把整个文件读入内存。
input_path = "input.txt"
output_path = "cleaned.txt"
excluded_keyword = "DEBUG"

with open(input_path, "r", encoding="utf-8") as source:
    with open(output_path, "w", encoding="utf-8") as target:
        for line in source:
            # 跳过空行和只包含空白字符的行
            if line.strip() == "":
                continue

            # 跳过包含指定关键词的行
            if excluded_keyword in line:
                continue

            # 只移除行尾换行符,保留其他内容
            clean_line = line.rstrip("rn")

            target.write(clean_line + "n")

例如,原文件内容如下:

正常记录一

DEBUG 调试信息
正常记录二
   


正常记录三

处理后,cleaned.txt 中只会保留:

正常记录一
正常记录二
正常记录三

这里的筛选条件可以根据实际需求修改。例如,筛选包含某个词的行:

if "error" in line.lower():
    target.write(line)

lower() 可以让大小写不同的英文内容也被视为相同。若只想保留包含关键词的行,可以反过来写:

if "success" not in line.lower():
    continue

target.write(line)

一个更完整的文本清洗脚本

如果希望同时清理首尾空白、跳过空行并过滤关键词,可以把逻辑集中在一个循环中:

input_path = "input.txt"
output_path = "cleaned.txt"
blocked_words = ["DEBUG", "TRACE"]

with open(input_path, "r", encoding="utf-8") as source, 
     open(output_path, "w", encoding="utf-8") as target:

    for line in source:
        clean_line = line.strip()

        # 跳过空行
        if not clean_line:
            continue

        # 跳过包含任意屏蔽词的行
        if any(word in clean_line for word in blocked_words):
            continue

        target.write(clean_line + "n")

print(f"清洗完成,结果已写入:{output_path}")

这个版本会删除每行开头和结尾的空格。如果原文本中的缩进具有实际意义,例如代码或配置内容,就不应使用 strip() 作为最终写入内容,而应该只用它进行空行判断:

if not line.strip():
    continue

clean_line = line.rstrip("rn")
target.write(clean_line + "n")

常见问题和处理方式

如果文件不存在,open() 会报错。可以在打开前检查路径:

from pathlib import Path

input_path = Path("input.txt")

if not input_path.exists():
    print("找不到输入文件")
else:
    with input_path.open("r", encoding="utf-8") as file:
        for line in file:
            print(line, end="")

如果输出文件已经存在,使用 "w" 会覆盖它。需要保留旧内容时,应改用 "a",但文本清洗通常需要重新生成完整结果,因此覆盖模式更符合预期。

还要注意读取和写入的编码应保持一致。比如读取时使用 UTF-8,写入时也使用 UTF-8:

with open("input.txt", "r", encoding="utf-8") as source, 
     open("output.txt", "w", encoding="utf-8") as target:
    for line in source:
        target.write(line)

对于普通清洗脚本,可以按照“明确编码、逐行读取、先判断空行、再执行筛选、最后写入”的顺序组织代码。这样既能减少乱码问题,也能避免不必要的内存占用,并且更容易在后续增加新的筛选条件。

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享