首页 > 解决方案 > 如何使用Java根据键读取文件并按行分组到一个新文件中

问题描述

我是 Java 新手,必须实现以下逻辑。我必须读取整个文件(大约 50 MB)并根据文件中存在的 invoiceNum(key) 上的 group by 编写一个新文件。

例如 -

我的文件内容是

DETAIL|8834|2020-02-14|31|1964|abc|acb||SG|SG|802|||||||1200.0000|8147DBD670B74E65A848|3584453|abc
DETAIL|8834|2020-02-14|32|1964|abc|abc||SG|SG|802|||||||1200.0000|8147DBD670B74E65A848|3584453|abc
DETAIL|8834|2020-02-14|33|1964|abc|abc||SG|SG|802|||||||1200.0000|8147DBD670B74E65A848|3584453|abc
DETAIL|8834|2020-02-14|34|1964|abc|abc||SG|SG|802|||||||1200.0000|8147DBD670B74E65A848|3584453|abc
DETAIL|8834|2020-02-14|35|1964|abc|abc||SG|SG|802|||||||1200.0000|8147DBD670B74E65A848|3584453|abc
DETAIL|8834|2020-02-14|36|1964|abc|abc||SG|SG|802|||||||1232.3700|8147DBD670B74E65A848|3584453|abc
DETAIL|8834|2020-02-14|34|1964|abc|abc||SG|SG|802|||||||1200.0000|8147DBD670B74E65A848|3584455|abc
DETAIL|8834|2020-02-14|35|1964|abc|abc||SG|SG|802|||||||1200.0000|8147DBD670B74E65A848|3584455|abc
DETAIL|8834|2020-02-14|36|1964|abc|abc||SG|SG|802|||||||1232.3700|8147DBD670B74E65A848|3584455|abc

在这个文件内容中,我有 2 个发票号(3584453 和 3584455)所以第 5 行属于发票号 - 3584453,所有 5 行都应该复制到新文件中,比如 test1.txt,剩下的 2 行属于发票号 - 3584455 和这些2行应该被复制到新文件说test2.txt

我将有大约 15k 行文件,我应该为所有唯一的发票编号创建新文件。我正在使用 jdk 7。

有人可以帮忙解决这个逻辑吗?

谢谢你。

标签: javagroup-by

解决方案


一个简单的解决方案(虽然不是很有效)是将整个文件的内容加载到内存中,例如使用Files.readAllLines(Path, Charset)然后将数据分组到Map<String, List<String>表示从发票 ID 到属于该发票 ID 的行的映射:

Map<String, List<String>> groupedData = new HashMap<>();
for (String line: lines) {
    String[] split = line.split("\\|");
    String invoiceId = split[<index_of_id>]
    List<String> groupedLines = groupedData.computeIfAbsent(invoiceId, (key) -> new ArrayList<>());
    groupedLines.add(line);
 }

然后,您可以遍历地图中的所有条目并将其保存到单个文件中(再次查看Files API)。

有更好的解决方案涉及例如 Streams,这样文件的全部内容就不会一次存储在内存中,但是 Files API 应该为您提供一个很好的起点,也许该解决方案对于您的用例来说甚至足够有效。


推荐阅读