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

如何使用Java Streams及java.nio.file.Files逐行合并两个大文本文件

使用Java Streams实现文件对应行拼接

可以用Java Streams结合java.nio.file.Files实现需求,核心是实现流的配对(zip)操作——Java标准库没有内置流zip方法,我们可以通过Spliterator同步遍历两个文件的行流,处理文件长度不一致的情况。

你之前尝试的Stream.of(Files.lines(...), Files.lines(...)).flatMap(...)思路存在误区:flatMap是将多个流的元素平铺为单个流,而我们需要把两个流的对应元素配对(第一行配第一行、第二行配第二行),因此需要自定义zip逻辑。

完整流实现代码

package com.example.codingTest;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Iterator;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.BinaryOperator;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

public class FileMergerImpl {

    public void merge(Path sourceFilename1, Path sourceFilename2, Path targetFilename, BinaryOperator<String> lineCombiner) {
        // try-with-resources保证流自动关闭,避免资源泄漏
        try (Stream<String> lines1 = Files.lines(sourceFilename1);
             Stream<String> lines2 = Files.lines(sourceFilename2)) {

            // 生成配对流:每个元素为两个文件的对应行,某一文件耗尽时对应位置为null
            Stream<Pair<String, String>> pairedLines = zip(lines1, lines2);

            // 按照需求处理配对行,生成最终内容
            Stream<String> mergedLines = pairedLines.map(pair -> {
                String line1 = pair.left;
                String line2 = pair.right;
                if (line1 != null && line2 != null) {
                    return lineCombiner.apply(line1, line2);
                } else if (line1 != null) {
                    return line1;
                } else {
                    return line2;
                }
            });

            // 将合并后的行写入目标文件,迭代器方式避免加载全部内容到内存
            Files.write(targetFilename, (Iterable<String>) mergedLines::iterator);

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    // 自定义流zip方法,同步遍历两个流直到全部耗尽
    private <T, U> Stream<Pair<T, U>> zip(Stream<T> first, Stream<U> second) {
        Iterator<T> iterator1 = first.iterator();
        Iterator<U> iterator2 = second.iterator();

        Spliterator<Pair<T, U>> spliterator = Spliterators.spliteratorUnknownSize(
                new Iterator<>() {
                    @Override
                    public boolean hasNext() {
                        return iterator1.hasNext() || iterator2.hasNext();
                    }

                    @Override
                    public Pair<T, U> next() {
                        T t = iterator1.hasNext() ? iterator1.next() : null;
                        U u = iterator2.hasNext() ? iterator2.next() : null;
                        return new Pair<>(t, u);
                    }
                },
                Spliterator.ORDERED
        );

        return StreamSupport.stream(spliterator, false);
    }

    // 内部配对类,用于存储两个流的对应元素
    private static class Pair<L, R> {
        final L left;
        final R right;

        Pair(L left, R right) {
            this.left = left;
            this.right = right;
        }
    }
}

代码关键点说明

  1. zip方法:通过迭代器同步遍历两个流,当其中一个流耗尽时返回null,确保两个文件的所有行都被处理,适配长度不一致的场景。
  2. 合并逻辑:和你原有的非流实现完全一致,保证行为相同,可直接通过原单元测试。
  3. 内存友好:流的惰性求值特性+Files.write的迭代器写入方式,不会一次性加载所有文件内容到内存,适合处理大型文本文件。

内容的提问来源于stack exchange,提问作者Lucas T

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 00:27:33