如何提取大于 10 GB 且 4GB RAM 的文件中的唯一行
How to extract unique lines in file > 10 GB with 4GB RAM
我有一台 4 GB RAM 的 PC 和一个 10 GB 内存使用量的文件。现在我想检查文件中的每一行是否都是唯一的,所以我编写了以下代码:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
public class Cleaner {
public static void main(String[] args) throws IOException {
if (args.length < 2) {
System.out.println("Too less parameters!");
return;
}
File file = new File(args[0]);
BufferedReader buff = new BufferedReader(new FileReader(file));
String line;
Set<String> set = new HashSet<String>();
while ((line = buff.readLine()) != null) {
set.add(line);
}
FileWriter fw = new FileWriter(args[1]);
for (String s : set) {
fw.write(s + "\n");
fw.flush();
}
fw.close();
buff.close();
}
}
但是我遇到了 OutOfMemoryException,所以我的问题是:
我应该如何更改我的代码以获得每行都是唯一的文件?
提前感谢您的帮助。
由于您的 RAM 内存,您不能以那种方式执行该操作。相反,您可以读取文件并生成 n 个固定大小的文件(f.e:10.000 行)读取一行并将其放入实际文件中。当您达到文件限制时,打开一个新文件并释放所有对象以保存内存,然后进行第二个循环并使用字符串(对于该行)将原始文件的每一行与 n 生成的文件进行比较。也许这样你可以避免内存间隙。
有点奇怪,过程会很慢,但我认为这样你可以达到你的要求。
如果您需要代码,请告诉我。
希望有所帮助
您可以先尝试查找重复行的哈希值以识别潜在的重复行:
Map<Integer, Integer> hashes = new HashMap<> ();
Map<Integer, Integer> dupes = new HashMap<> ();
int i = 0;
while ((line = buff.readLine()) != null) {
int hash = line.hashCode();
Integer previous = hashes.get(hash);
if (previous != null) { //potential duplicate
dupes.put(i, previous);
} else {
hashes.put(hash, i);
}
++i;
}
最后你有一个可能重复的列表。如果 dupes
为空则没有重复项,如果不是则您可以对文件进行第二次传递以检查行是否真的相同。
你可以用这样的东西作弊:(示例是 Groovy,但等效的 Java 也可以)
def hashes = []
def writer = new PrintWriter(new FileWriter("out.txt"))
new File('test.txt').eachLine { line ->
def hashCode = DigestUtils.sha256Hex(line) //Commons digest library
if (!(hashCode in hashes)) {
hashes << hashCode
writer.println(line)
}
}
writer.close()
运行 需要的 RAM 不应超过 1GB。与标准 hashCode
方法相比,SHA256 哈希值可能会让您更加确定一行的唯一性。
我有一台 4 GB RAM 的 PC 和一个 10 GB 内存使用量的文件。现在我想检查文件中的每一行是否都是唯一的,所以我编写了以下代码:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
public class Cleaner {
public static void main(String[] args) throws IOException {
if (args.length < 2) {
System.out.println("Too less parameters!");
return;
}
File file = new File(args[0]);
BufferedReader buff = new BufferedReader(new FileReader(file));
String line;
Set<String> set = new HashSet<String>();
while ((line = buff.readLine()) != null) {
set.add(line);
}
FileWriter fw = new FileWriter(args[1]);
for (String s : set) {
fw.write(s + "\n");
fw.flush();
}
fw.close();
buff.close();
}
}
但是我遇到了 OutOfMemoryException,所以我的问题是:
我应该如何更改我的代码以获得每行都是唯一的文件?
提前感谢您的帮助。
由于您的 RAM 内存,您不能以那种方式执行该操作。相反,您可以读取文件并生成 n 个固定大小的文件(f.e:10.000 行)读取一行并将其放入实际文件中。当您达到文件限制时,打开一个新文件并释放所有对象以保存内存,然后进行第二个循环并使用字符串(对于该行)将原始文件的每一行与 n 生成的文件进行比较。也许这样你可以避免内存间隙。
有点奇怪,过程会很慢,但我认为这样你可以达到你的要求。
如果您需要代码,请告诉我。
希望有所帮助
您可以先尝试查找重复行的哈希值以识别潜在的重复行:
Map<Integer, Integer> hashes = new HashMap<> ();
Map<Integer, Integer> dupes = new HashMap<> ();
int i = 0;
while ((line = buff.readLine()) != null) {
int hash = line.hashCode();
Integer previous = hashes.get(hash);
if (previous != null) { //potential duplicate
dupes.put(i, previous);
} else {
hashes.put(hash, i);
}
++i;
}
最后你有一个可能重复的列表。如果 dupes
为空则没有重复项,如果不是则您可以对文件进行第二次传递以检查行是否真的相同。
你可以用这样的东西作弊:(示例是 Groovy,但等效的 Java 也可以)
def hashes = []
def writer = new PrintWriter(new FileWriter("out.txt"))
new File('test.txt').eachLine { line ->
def hashCode = DigestUtils.sha256Hex(line) //Commons digest library
if (!(hashCode in hashes)) {
hashes << hashCode
writer.println(line)
}
}
writer.close()
运行 需要的 RAM 不应超过 1GB。与标准 hashCode
方法相比,SHA256 哈希值可能会让您更加确定一行的唯一性。