【发布时间】:2018-09-14 21:21:24
【问题描述】:
我想从文本文件中删除重复的字符串。为了做到这一点,我将每一行放在一个 HashSet 中,然后将它们写入另一个文件。它工作正常。但是当涉及到大文件(180mb 500 万行)时,它就不能很好地工作了。假设不可能在 HashSet 或任何其他集合中存储 500 万个字符串,我做了一个循环,所以我存储了前 100 000 行,然后将它们写入文件,然后清除 HashSet 并再次写入,直到出现文件中没有更多行。不幸的是,这不会删除所有重复项,但我认为它可以删除大约 70-90% 的重复项。但它不起作用。当我用 500 万行的 180mb 文件测试它时。我计算了大约 300 000 个重复项,新文件大约有 300 万行。它应该有大约 500 万 - 300 000。当我计算迭代时,它们应该是 500 万,但它们是 340 万。
public File removeDuplicates(File file) {
System.out.println("file opened");
Scanner sc;
HashSet<String> set = new HashSet<String>();
JFileChooser chooser = new JFileChooser();
File createdFile = null;
int returnVal = chooser.showSaveDialog(parent);
if (returnVal == JFileChooser.APPROVE_OPTION) {
BufferedWriter bufferedWriter = null;
createdFile = chooser.getSelectedFile();
try {
if (!createdFile.exists()) {
createdFile.createNewFile();
}
}catch(Exception e) {
e.printStackTrace();
}
}
try {
sc = new Scanner(file);
boolean hasMore = true;
while (hasMore) {
hasMore = false;
while (sc.hasNextLine() && set.size() < PERIOD) {
set.add(sc.nextLine());
repeated++;
}
createdFile = this.writeToFile(set,createdFile);
set.clear();
hasMore = true;
if (sc.hasNextLine() == false)
hasMore = false;
set.clear();
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return createdFile;
}
private File writeToFile(HashSet<String> set, File f) {
BufferedWriter bufferedWriter = null;
try {
Writer writer = new FileWriter(f, true);
bufferedWriter = new BufferedWriter(writer);
for (String str : set) {
bufferedWriter.write(str);
bufferedWriter.newLine();
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if (bufferedWriter != null)
try {
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return f;
}
repeated 是计算迭代次数的变量。 是来自代码还是来自 RAM 消耗?有没有办法让它工作?
【问题讨论】:
-
但是当涉及到大文件(180mb 500 万行)时,它不能很好地工作是什么意思?具体是什么问题?
-
例如……什么?
-
Assuming the fact that it is not possible to store 5 million strings in a HashSet or any other collection等等,这个假设从何而来? It seems to be wrong。与实际设置实现相比,您更可能受到内存大小(和 JVM 内存限制)的限制。即使这样,也可能会有处理更多元素的实现......只要你能节省内存。 -
话虽如此,大幅减少内存消耗可能相对简单 - 从 file1 读取行,检查它是否在 file2 中,如果不是 -> 将其写入 file2。不过,这会做更多的磁盘读取,但如果你不能节省内存,它会避免占用内存。
-
180mb 真的不算多,即使是在谈论虚拟内存时也是如此。我建议您调试脚本与完整文件一起挂起的原因(您可能需要先检查 GC 日志以查看它是否在全时运行,在这种情况下增加 JVM 的 XMX)。您总是可以通过存储行的哈希而不是它们的全部内容来牺牲 CPU 来赢得内存,但我怀疑您是否会想要牺牲读取每个记录的整个文件所需的时间,正如@vlaz 曾经建议的那样。
标签: java