如何高效去除文件末尾换行符并提取H:到T:间数据


阅读 4 次

问题场景描述

在处理金融数据交换文件时,经常会遇到需要清理文件格式的情况。比如下面这个典型的数据文件:

H:20050427 HEADER RECORD
0000000 00000 000000000 123456 00 654321 DATARECORD
0000000 00000 000000000 123456 00 654321 DATARECORD
0000000 00000 000000000 123456 00 654321 DATARECORD
0000000 00000 000000000 123456 00 654321 DATARECORD
T:20050427 TRAILER RECORD

注意文件末尾有一个多余的空行(显示为[blank space]),我们需要:

  1. 去除文件末尾所有空白行
  2. 提取H:和T:标记之间的有效数据
  3. 生成新的规范化文件

Python解决方案

使用Python可以很优雅地解决这个问题:

def process_flat_file(input_path, output_path):
    with open(input_path, 'r') as f:
        lines = [line.rstrip('\n') for line in f]
    
    # 去除末尾空行
    while lines and not lines[-1].strip():
        lines.pop()
    
    # 提取H:到T:之间的数据
    start_idx = next(i for i, line in enumerate(lines) if line.startswith('H:'))
    end_idx = next(i for i, line in enumerate(lines) if line.startswith('T:'))
    
    valid_lines = lines[start_idx:end_idx+1]
    
    with open(output_path, 'w') as f:
        f.write('\n'.join(valid_lines))

# 使用示例
process_flat_file('input.dat', 'output.dat')

Shell脚本方案

对于习惯使用命令行工具的用户,可以用sed和awk组合:

#!/bin/bash
# 去除末尾空行并提取H:到T:间内容
sed -i ':a;/^\n*$/{$d;N;ba}' input.dat
awk '/^H:/,/^T:/' input.dat > output.dat

Java实现方案

企业级应用中可能需要Java实现:

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class FileProcessor {
    public static void processFile(String inputPath, String outputPath) throws IOException {
        List<String> lines = new ArrayList<>();
        try (BufferedReader br = new BufferedReader(new FileReader(inputPath))) {
            String line;
            while ((line = br.readLine()) != null) {
                lines.add(line);
            }
        }
        
        // 去除末尾空行
        while (!lines.isEmpty() && lines.get(lines.size()-1).trim().isEmpty()) {
            lines.remove(lines.size()-1);
        }
        
        // 提取有效数据
        int start = -1, end = -1;
        for (int i = 0; i < lines.size(); i++) {
            if (lines.get(i).startsWith("H:")) start = i;
            if (lines.get(i).startsWith("T:")) end = i;
        }
        
        if (start == -1 || end == -1) {
            throw new IllegalArgumentException("Invalid file format");
        }
        
        try (PrintWriter pw = new PrintWriter(new FileWriter(outputPath))) {
            for (int i = start; i <= end; i++) {
                pw.println(lines.get(i));
            }
        }
    }
}

性能优化建议

处理大文件时需要注意:

  • 使用流式处理而非全量读取
  • 考虑使用内存映射文件(MappedByteBuffer)
  • 对于GB级文件,建议分块处理

这里给出一个Python的流式处理改进版:

def stream_process(input_path, output_path):
    with open(input_path, 'r') as fin, open(output_path, 'w') as fout:
        in_section = False
        buffer = []
        
        for line in fin:
            line = line.rstrip('\n')
            
            if line.startswith('H:'):
                in_section = True
                buffer = [line]
            elif line.startswith('T:'):
                if in_section:
                    buffer.append(line)
                    fout.write('\n'.join(buffer) + '\n')
                in_section = False
            elif in_section:
                buffer.append(line)

常见问题排查

实际应用中可能遇到:

  1. 文件编码问题:建议统一使用UTF-8
  2. 行尾符差异:Windows(CRLF)和Linux(LF)的区别
  3. 大文件内存溢出:使用上文提到的流式处理