【发布时间】:2019-06-10 12:06:14
【问题描述】:
我有 100 个包含以下内容的 CSV 文件
name,price
book,12.4
bread,54.23
每个文件显示内容按价格顺序排序 我需要通过所有这些文件找到 10 个最昂贵的产品。这是我的代码:
import org.apache.commons.io.FileUtils;
import org.junit.Assert;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import static java.util.stream.Collectors.toList;
public final class FindBiggest extends Assert {
static class Data {
public Data(String str) {
final String[] split = str.split(",");
this.name = split[0];
this.price = Float.parseFloat(split[1]);
}
private final String name;
private final float price;
}
@Test
public void test() throws Exception {
final List<File> files = Files.walk(Paths.get("/tmp/"))
.filter(Files::isRegularFile)
.filter(path -> path.toString().endsWith(".csv"))
.map(Path::toFile)
.collect(toList());
final List<Data> collect =
files.stream()
.map(FindBiggest::content)
.map(Data::new)
.sorted((o1, o2) -> Float.compare(o1.price, o2.price))
.limit(10)
.collect(toList());
System.out.println(collect);
}
private static String content(final File file) {
try {
return FileUtils.readFileToString(file, StandardCharsets.UTF_8);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}
如果我有很多 csv 文件程序抛出 UOM(Out of memory) 如何实现程序对所有文件中的内容进行排序而不将所有数据加载到内存?
【问题讨论】:
-
如果文件按价格排序,您不必从文件中读取所有数据。只需从每个文件中获取 10 条第一条记录。它为您提供了 1000 个最大价格元素的列表,然后您需要对该列表进行排序并获取前 10 个元素
-
我建议使用缓冲区,如果值大于处理的旧文件,则逐行评估每个文件。这样你就不需要将整个文件加载到内存中。
-
@ngueno 假设在第一个文件中的价格是 50 和 40 在第二个文件中 price 30 ,我加载 8 行,然后我将从第一个文件加载 price 50 到第二个文件并加载 price 30 ,但 40 比 30 大
-
@RafałSokalski 排序并不意味着单独文件中的价格需要相等,例如第一个文件可以包含价格 50、40、20,第二个文件可以包含 30、10、5,如果我只加载一个来自第一个文件,第二个我将有 50 和 30
-
@AlmasAbdrazak,好的,所以你需要一个包含 10 个最大价格的结构(例如列表/集合/地图),第一步是逐行读取每个文件,与此结构的内容,如果它大于某些内容,则将其替换为新值。这样,您将读取所有文件,并以不同的结构保持最大价格,而无需将整个内容加载到内存中,因为您将逐行评估值。
标签: java csv io out-of-memory