如何写文本分割合并脚本

wen 实用脚本 29

从零开始的实战指南

📖 目录导读

  1. 为什么你需要文本分割/合并脚本?——核心场景与痛点
  2. 基础原理:分割与合并的核心逻辑剖析
  3. 实战案例:用Python写一个万能文本分割脚本(带问答)
  4. 实战案例:智能文本合并脚本的三种写法(带问答)
  5. 高级技巧:处理大文件、编码问题与性能优化
  6. 常见错误避坑指南(含问答)
  7. 总结与工具推荐

为什么你需要文本分割/合并脚本?

在日常工作中,你是否遇到过这些场景?

如何写文本分割合并脚本

  • 一个日志文件高达2GB,普通编辑器打不开,需要按日期或关键字分割成小文件
  • 从多个数据源收集了100个CSV片段,需要合并成一个完整表格
  • 处理爬虫抓取的HTML片段,需要按指定规则拆分成独立页面
  • 需要将长篇小说按章节自动分割成单独文档

核心痛点:手动操作耗时易错,且无法重复利用,而一个能自动识别规则、处理各种编码、支持大文件的脚本,能瞬间解决这些难题。

SEO关键词提示:文本分割合并脚本、大文件处理、Python自动化、数据清洗。


基础原理:分割与合并的核心逻辑

分割(Split)的两种模式

模式 原理 适用场景
按大小分割 固定字节数或行数切割 日志按1000行分文件

合并(Merge)的三种策略

  • 简单拼接:直接按文件列表顺序读取写入
  • 去重合并:合并前去除重复行
  • 智能合并:根据时间戳或ID排序后合并

重要概念:文件编码(UTF-8/GBK)、缓冲区大小(影响大文件性能)、分隔符策略(影响分割准确性)。


实战案例:用Python写一个万能文本分割脚本

案例需求

data.log文件(500MB)按每1000行分割成多个小文件,文件名自动编号。

# split_log.py
import os
def split_file_by_lines(input_file, lines_per_file=1000, output_dir="split_output"):
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
    file_counter = 1
    line_counter = 0
    out_file = None
    with open(input_file, 'r', encoding='utf-8', errors='ignore') as f:
        for line in f:
            if line_counter % lines_per_file == 0:
                if out_file:
                    out_file.close()
                output_path = os.path.join(output_dir, f"part_{file_counter:04d}.txt")
                out_file = open(output_path, 'w', encoding='utf-8')
                file_counter += 1
            out_file.write(line)
            line_counter += 1
    if out_file:
        out_file.close()
    print(f"分割完成,共生成{file_counter-1}个文件")
# 使用示例
split_file_by_lines("huge_log.txt", lines_per_file=500)

🤔 问答:为什么我的脚本分割后文件顺序乱了?

:我用按大小分割时,一个文件被切成了两半,数据不完整怎么办?
:按字节分割时容易切断行数据,建议使用按行数分割(如上面代码),或者增加缓冲检测:先读一行,再判断大小,更健壮的方法是使用linecache模块或流式读取时保留行完整性。

:分割中文文本时出现乱码?
:常见原因是原始文件编码不是UTF-8,解决方案:先用chardet库检测编码,或强制指定encoding='gbk',建议在脚本开头加入编码探测:

import chardet
with open('data.txt', 'rb') as f:
    raw = f.read(10000)
    encoding = chardet.detect(raw)['encoding']

智能文本合并脚本的三种写法

简单合并(适合同类文件)

def simple_merge(file_list, output_file):
    with open(output_file, 'w', encoding='utf-8') as out:
        for f_path in file_list:
            with open(f_path, 'r', encoding='utf-8') as f:
                out.write(f.read())
                out.write('\n')  # 添加分隔

按文件名前缀合并(自动排序)

import glob, re
def merge_sorted(pattern="part_*.txt", output="merged.txt"):
    files = sorted(glob.glob(pattern), key=lambda x: 
                  int(re.findall(r'\d+', x)[0]))
    simple_merge(files, output)

逐行交错合并(多线程文件同步)

def interleave_merge(file1, file2, output):
    with open(file1) as f1, open(file2) as f2, open(output, 'w') as out:
        for line1, line2 in zip(f1, f2):
            out.write(line1.rstrip() + '\t' + line2)
        # 处理余下的行
        for remaining in [f1, f2]:
            for line in remaining:
                out.write(line)

🤔 问答:合并CSV时出现表头重复怎么办?

:合并10个CSV文件,每个都有表头,结果最后文件里有10个表头,怎么去掉多余的表头?
:在循环中加入判断:只保留第一个文件的表头,其余跳过第一行。

first = True
for f_path in csv_files:
    with open(f_path) as f:
        if first:
            out.write(f.read() + '\n')
            first = False
        else:
            next(f)  # 跳过第一行
            out.write(f.read() + '\n')

:合并文件时内存占用过高怎么办?
:使用行级流处理,不要一次性读入内存,上述代码已经体现了逐行处理的优点,对于超大型文件,可以设置buffer_size=65536字节读取。


高级技巧:大文件与性能优化

技巧1:使用with语句自动管理资源

避免文件未关闭导致的资源泄漏。

技巧2:设置合适缓冲区

with open('big.txt', 'rb', buffering=1<<20) as f:  # 1MB缓冲区

对于4GB以上文件,建议使用mmap(内存映射文件)实现极速处理。

技巧3:多线程异步分割

from concurrent.futures import ThreadPoolExecutor
def split_parallel(input_file, chunk_count=4):
    # 先统计总行数,然后计算每个线程负责的行数
    total_lines = sum(1 for _ in open(input_file))
    chunk_size = total_lines // chunk_count
    def worker(start, end, idx):
        # 具体分割逻辑...
        pass
    with ThreadPoolExecutor() as executor:
        futures = [executor.submit(worker, i*chunk_size, (i+1)*chunk_size, i) 
                   for i in range(chunk_count)]

技巧4:编码自动识别与转换

# 命令行工具快速检测编码
chardetect input.txt > encoding_info.txt

常见错误避坑指南

🔴 错误1:忘记处理文件结尾

问题:最后一个分割文件丢失数据。
解决:使用for-elsefinally确保最后一个文件被关闭。

🔴 错误2:文件路径硬编码

问题:脚本不通用。
解决:使用argparsesys.argv接收用户参数。

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('input_file')
parser.add_argument('--lines', type=int, default=1000)
args = parser.parse_args()

🔴 错误3:忽略不可见字符

现象:合并后文件出现奇怪转义符。
处理:写之前用.rstrip('\n').strip()清理。

🤔 问答:如何在Linux/Windows间兼容?

:脚本在Windows上运行时,换行符变成\r\n导致分割异常?
:打开文件时使用newline=''参数禁止自动换行转换,或者统一使用二进制模式'rb''wb'

with open('data.txt', 'rb') as f, open('out.txt', 'wb') as out:
    for line in f:
        out.write(line)  # 二进制模式不会转换换行符

总结与推荐工具

📈 关键要点回顾

场景 最佳策略 推荐方法
按行分割 流式读取+行计数 Python for循环
合并大量小文件 排序后逐文件写入 glob+lambda排序
处理特大文件 二进制模式+缓冲区 mmap或pandas chunksize

🔧 常用工具速查

  1. Python标准库osglobreiocodecs
  2. 第三方库chardet(编码检测)、pandas(CSV合并)、collections(去重)
  3. 命令行替代方案
    • Linux: split -l 1000 input.txt / cat part* > merged.txt
    • Windows: type *.txt > combined.txt

💡 终极建议

编写文本分割合并脚本时,记住这个公式: 脚本健壮性 = 编码处理 + 边界条件 + 资源释放 + 错误日志

将所有关键参数(输入路径、行数、编码)做成命令行参数,这样你的脚本就能成为团队通用的自动化工具,甚至可以直接集成到你的CI/CD流水线中。

立刻动手:用一个100行的日志文件测试上面的代码,然后尝试修改成可以自动从文件名提取分隔标记(如“2024-01-01”等)的版本,你会发现,真正的效率提升从第一个成功的分割开始。

抱歉,评论功能暂时关闭!