Ithy Logo

使用 Python 合并一个文件夹下的多个 TXT 文件的全面指南

How to get a list of python modules (with version for each module) and ...

前提条件

  • 已安装Python 3.x版本。可以通过在终端或命令提示符中运行 python --version 来检查当前安装的版本。
  • 基础的Python编程知识,包括文件操作和异常处理。
  • 在需要处理编码检测的高级功能时,建议安装 chardet 库。可以使用以下命令安装:
pip install chardet

基本实现方法:使用 os 模块

Python的 os 模块提供了丰富的文件和目录操作功能。以下是一个基本的脚本,用于合并指定文件夹下的所有TXT文件:

步骤一:导入必要的模块

import os

步骤二:定义文件夹路径和输出文件路径

folder_path = "path/to/your/folder"  # 替换为实际的文件夹路径
output_file = "path/to/your/output/merged_result.txt"  # 替换为实际的输出文件路径

步骤三:获取所有TXT文件并合并

def merge_txt_files(folder_path, output_file):
    # 获取文件夹中所有的TXT文件
    txt_files = [f for f in os.listdir(folder_path) if f.endswith('.txt')]
    
    # 按文件名排序(可选)
    txt_files.sort()
    
    with open(output_file, 'w', encoding='utf-8') as outfile:
        for txt_file in txt_files:
            file_path = os.path.join(folder_path, txt_file)
            with open(file_path, 'r', encoding='utf-8') as infile:
                outfile.write(f"\\n--- {txt_file} ---\\n")  # 添加文件分隔标记
                outfile.write(infile.read())
                outfile.write('\\n')  # 添加换行符分隔内容
    
    print(f"所有TXT文件已成功合并到 {output_file}")

if __name__ == "__main__":
    merge_txt_files(folder_path, output_file)

代码解释

  1. 获取TXT文件列表:使用 os.listdir() 列出文件夹中的所有文件,并通过列表推导式过滤出以 ".txt" 结尾的文件。
  2. 排序文件:可选步骤,通过 txt_files.sort() 对文件名进行排序,确保合并顺序的一致性。
  3. 合并文件内容:使用 with open() 以写入模式打开目标输出文件。然后遍历每个TXT文件,读取内容并写入目标文件,同时在每个文件内容之前添加分隔标记和换行符,以便后续查看时区分不同文件的内容。
  4. 执行合并:通过调用 merge_txt_files() 函数,传入文件夹路径和输出文件路径,完成合并操作。

进阶方法:使用 glob 模块处理更复杂的文件匹配

当需要合并的TXT文件分布在多个子目录中,或需要更复杂的文件匹配规则时,glob 模块会非常有用。以下是使用 glob 模块进行文件搜索和合并的示例:

步骤一:导入必要的模块

import os
import glob

步骤二:定义合并函数

def merge_txt_files_glob(folder_path, output_file, recursive=False, add_filename=False):
    """
    合并指定文件夹下所有TXT文件到一个输出文件中。

    :param folder_path: 包含TXT文件的文件夹路径
    :param output_file: 输出的合并后TXT文件路径
    :param recursive: 是否递归查找子文件夹,默认为False
    :param add_filename: 是否在每个文件内容前添加文件名,默认为False
    """
    if recursive:
        pattern = os.path.join(folder_path, '**', '*.txt')
    else:
        pattern = os.path.join(folder_path, '*.txt')
    
    txt_files = glob.glob(pattern, recursive=recursive)
    txt_files.sort()
    
    with open(output_file, 'w', encoding='utf-8') as outfile:
        for filename in txt_files:
            if add_filename:
                outfile.write(f"\\n--- {os.path.basename(filename)} ---\\n")
            with open(filename, 'r', encoding='utf-8') as infile:
                outfile.write(infile.read())
                outfile.write('\\n')
    
    print(f"所有TXT文件已成功合并到 {output_file}")

使用示例

if __name__ == "__main__":
    folder_path = 'path/to/your/txt_files'  # 替换为实际的文件夹路径
    output_file = 'path/to/your/output/merged.txt'  # 替换为实际的输出文件路径
    merge_txt_files_glob(folder_path, output_file, recursive=True, add_filename=True)

在这个示例中,recursive=True 表示将递归地查找所有子文件夹中的TXT文件,add_filename=True 则在每个文件内容前添加文件名作为分隔标记,便于区分不同源文件的内容。

处理文件编码问题

在实际操作中,不同的TXT文件可能采用不同的编码格式,特别是在处理中文内容时。为了确保正确读取文件内容,可以使用 chardet 库自动检测文件编码,并相应地进行解码:

安装 chardet

pip install chardet

实现编码检测和错误处理

import os
import glob
import chardet

def detect_encoding(file_path):
    """检测文件编码"""
    with open(file_path, 'rb') as file:
        raw_data = file.read()
        result = chardet.detect(raw_data)
        return result['encoding']

def merge_txt_files_advanced(folder_path, output_file, recursive=False, add_filename=False):
    """
    合并指定文件夹下所有TXT文件到一个输出文件中,自动检测编码并处理错误。

    :param folder_path: 包含TXT文件的文件夹路径
    :param output_file: 输出的合并后TXT文件路径
    :param recursive: 是否递归查找子文件夹,默认为False
    :param add_filename: 是否在每个文件内容前添加文件名,默认为False
    """
    if recursive:
        pattern = os.path.join(folder_path, '**', '*.txt')
    else:
        pattern = os.path.join(folder_path, '*.txt')
    
    txt_files = glob.glob(pattern, recursive=recursive)
    txt_files.sort()
    
    with open(output_file, 'w', encoding='utf-8') as outfile:
        for index, filename in enumerate(txt_files, 1):
            try:
                encoding = detect_encoding(filename)
                if add_filename:
                    outfile.write(f"\\n=== 文件 {index}: {os.path.basename(filename)} ===\\n")
                with open(filename, 'r', encoding=encoding) as infile:
                    contents = infile.read()
                    outfile.write(contents)
                    if not contents.endswith('\\n'):
                        outfile.write('\\n')
                print(f"成功合并文件: {os.path.basename(filename)}")
            except Exception as e:
                print(f"处理文件 {os.path.basename(filename)} 时出错: {str(e)}")
    
    print(f"合并完成,输出文件: {output_file}")

使用示例

if __name__ == "__main__":
    folder_path = 'path/to/your/txt_files'  # 替换为实际的文件夹路径
    output_file = 'path/to/your/output/merged_advanced.txt'  # 替换为实际的输出文件路径
    merge_txt_files_advanced(folder_path, output_file, recursive=True, add_filename=True)

处理大文件的优化方法

当需要合并的文件量大且单个文件尺寸较大时,一次性读取整个文件内容可能会导致内存占用过高。为了解决这一问题,可以采用分块读取的方式:

实现分块读取和写入

def merge_large_txt_files(folder_path, output_file, chunk_size=8192, recursive=False, add_filename=False):
    """
    合并大尺寸TXT文件,使用分块读取以优化内存使用。

    :param folder_path: 包含TXT文件的文件夹路径
    :param output_file: 输出的合并后TXT文件路径
    :param chunk_size: 每次读取的块大小(字节)
    :param recursive: 是否递归查找子文件夹,默认为False
    :param add_filename: 是否在每个文件内容前添加文件名,默认为False
    """
    if recursive:
        pattern = os.path.join(folder_path, '**', '*.txt')
    else:
        pattern = os.path.join(folder_path, '*.txt')
    
    txt_files = glob.glob(pattern, recursive=recursive)
    txt_files.sort()
    
    with open(output_file, 'w', encoding='utf-8') as outfile:
        for txt_file in txt_files:
            try:
                encoding = detect_encoding(txt_file)
                if add_filename:
                    outfile.write(f"\\n=== {os.path.basename(txt_file)} ===\\n")
                with open(txt_file, 'r', encoding=encoding) as infile:
                    while True:
                        chunk = infile.read(chunk_size)
                        if not chunk:
                            break
                        outfile.write(chunk)
                    outfile.write('\\n')  # 添加换行符分隔内容
                print(f"已处理: {os.path.basename(txt_file)}")
            except Exception as e:
                print(f"处理文件 {os.path.basename(txt_file)} 时出错: {str(e)}")
    
    print(f"合并完成,输出文件: {output_file}")

使用示例

if __name__ == "__main__":
    folder_path = 'path/to/your/large_txt_files'  # 替换为实际的文件夹路径
    output_file = 'path/to/your/output/merged_large.txt'  # 替换为实际的输出文件路径
    merge_large_txt_files(folder_path, output_file, chunk_size=16384, recursive=True, add_filename=True)

常见问题及解决方案

1. 如何处理不同编码格式的文件?

不同的TXT文件可能采用不同的编码格式,如UTF-8、GBK、ASCII等。使用 chardet 库可以自动检测文件编码,并根据检测结果进行解码。例如:

try:
    with open(file_path, 'r', encoding=detected_encoding) as infile:
        contents = infile.read()
except UnicodeDecodeError:
    with open(file_path, 'r', encoding='gbk') as infile:
        contents = infile.read()

2. 如何忽略隐藏文件或非文本文件?

在某些操作系统中,文件夹中可能包含隐藏文件或非TXT格式的文件。可以在文件筛选阶段增加条件:

if not filename.startswith('.') and filename.endswith('.txt')

3. 如何在合并的文件内容之间添加自定义分隔符?

为了更清晰地区分不同文件的内容,可以在写入内容时添加自定义分隔符,例如:

outfile.write('\\n==== 文件分割线 ====\\n')

4. 如何处理目录中没有TXT文件的情况?

在合并前,可以检查TXT文件列表是否为空,并给出相应提示:

if not txt_files:
    print("没有找到TXT文件进行合并。")
    return

扩展功能和优化建议

1. 递归合并子文件夹中的TXT文件

通过将 glob.glob()recursive 参数设置为 True,可以递归遍历所有子文件夹:

txt_files = glob.glob(os.path.join(folder_path, '**', '*.txt'), recursive=True)

2. 按文件大小或其他自定义规则排序

默认情况下,文件列表是按文件名排序的。若需按文件大小排序,可以使用以下代码:

txt_files.sort(key=lambda x: os.path.getsize(x))

3. 添加进度显示

对于大量文件合并,添加进度显示可以提升用户体验。例如,使用 tqdm 库实现进度条:

pip install tqdm
from tqdm import tqdm

for txt_file in tqdm(txt_files, desc="合并进度"):
    # 合并逻辑

4. 日志记录

为了更好地追踪合并过程,可以将日志信息写入日志文件,而不仅仅是打印到控制台:

import logging

logging.basicConfig(filename='merge_log.txt', level=logging.INFO, 
                    format='%(asctime)s - %(levelname)s - %(message)s')

logging.info(f"开始合并文件到 {output_file}")
# 在合并过程中记录
logging.error(f"处理文件 {filename} 时出错: {e}")

完整示例代码

以下是一个集成了编码检测、错误处理、递归搜索和分块读取的高级合并脚本:

import os
import glob
import chardet
from tqdm import tqdm
import logging

logging.basicConfig(filename='merge_log.txt', level=logging.INFO, 
                    format='%(asctime)s - %(levelname)s - %(message)s')

def detect_encoding(file_path):
    """检测文件编码"""
    with open(file_path, 'rb') as file:
        raw_data = file.read()
        result = chardet.detect(raw_data)
        return result['encoding']

def merge_txt_files_full(folder_path, output_file, recursive=False, add_filename=False, chunk_size=8192):
    """
    完整的TXT文件合并函数,含编码检测、错误处理和进度显示。

    :param folder_path: 包含TXT文件的文件夹路径
    :param output_file: 输出的合并后TXT文件路径
    :param recursive: 是否递归查找子文件夹,默认为False
    :param add_filename: 是否在每个文件内容前添加文件名,默认为False
    :param chunk_size: 每次读取的块大小(字节),默认为8192
    """
    try:
        if recursive:
            pattern = os.path.join(folder_path, '**', '*.txt')
        else:
            pattern = os.path.join(folder_path, '*.txt')
        
        txt_files = glob.glob(pattern, recursive=recursive)
        txt_files.sort()
        
        if not txt_files:
            logging.warning("没有找到TXT文件进行合并。")
            print("没有找到TXT文件进行合并。")
            return
        
        with open(output_file, 'w', encoding='utf-8') as outfile:
            for txt_file in tqdm(txt_files, desc="合并进度"):
                try:
                    encoding = detect_encoding(txt_file)
                    if add_filename:
                        outfile.write(f"\\n=== {os.path.basename(txt_file)} ===\\n")
                    with open(txt_file, 'r', encoding=encoding) as infile:
                        while True:
                            chunk = infile.read(chunk_size)
                            if not chunk:
                                break
                            outfile.write(chunk)
                        outfile.write('\\n')  # 添加换行符分隔内容
                    logging.info(f"成功合并文件: {os.path.basename(txt_file)}")
                except Exception as e:
                    logging.error(f"处理文件 {os.path.basename(txt_file)} 时出错: {str(e)}")
        
        logging.info(f"所有TXT文件已成功合并到 {output_file}")
        print(f"合并完成,输出文件: {output_file}")
    except Exception as e:
        logging.critical(f"合并过程中的严重错误: {str(e)}")
        print(f"合并过程中发生严重错误: {str(e)}")

if __name__ == "__main__":
    folder_path = 'path/to/your/txt_files'  # 替换为实际的文件夹路径
    output_file = 'path/to/your/output/merged_full.txt'  # 替换为实际的输出文件路径
    merge_txt_files_full(folder_path, output_file, recursive=True, add_filename=True, chunk_size=16384)

参考资料

以下是一些有助于深入理解和扩展文件合并功能的资源:

结论

通过本文提供的方法,您可以使用Python高效地将一个文件夹下的多个TXT文件合并为一个文件。无论是简单的文件合并还是需要处理编码、递归搜索、错误处理和性能优化的复杂场景,本指南都提供了详尽的解决方案。根据您的具体需求,选择适合的脚本版本并进行必要的调整,以实现最佳的文件合并效果。如有进一步的问题或需要更高级的功能,建议参考上述参考资料或相关Python文档。


Last updated January 8, 2025
Ask me more