我有两个文件:
1- 1400,000行或记录--- 14 MB
2-与16000000 - 170 MB
我想查找文件1中的每个记录或行是否也在文件2中
我开发了一个执行以下操作的java应用程序:逐行读取文件并将每行传递给在文件2中循环的方法
这是我的代码:
public boolean hasIDin(String bioid) throws Exception {
BufferedReader br = new BufferedReader(new FileReader("C://AllIDs.txt"));
long bid = Long.parseLong(bioid);
String thisLine;
while((thisLine = br.readLine( )) != null)
{
if (Long.parseLong(thisLine) == bid)
return true;
}
return false;
}
public void getMBD() throws Exception{
BufferedReader br = new BufferedReader(new FileReader("C://DIDs.txt"));
OutputStream os = new FileOutputStream("C://MBD.txt");
PrintWriter pr = new PrintWriter(os);
String thisLine;
int count=1;
while ((thisLine = br.readLine( )) != null){
String bioid = thisLine;
System.out.println(count);
if(! hasIDin(bioid))
pr.println(bioid);
count++;
}
pr.close();
}
当我运行它似乎需要更多1944.44444444444小时才能完成,因为每行处理需要5秒。那是大约三个月!
是否有任何想法可以在更短的时间内完成。
提前致谢。
答案 0 :(得分:5)
你为什么不;
这是一个调整的实现,它打印以下内容并使用< 64 MB。
Generating 1400000 ids to /tmp/DID.txt
Generating 16000000 ids to /tmp/AllIDs.txt
Reading ids in /tmp/DID.txt
Reading ids in /tmp/AllIDs.txt
Took 8794 ms to find 294330 valid ids
代码
public static void main(String... args) throws IOException {
generateFile("/tmp/DID.txt", 1400000);
generateFile("/tmp/AllIDs.txt", 16000000);
long start = System.currentTimeMillis();
TLongHashSet did = readLongs("/tmp/DID.txt");
TLongHashSet validIDS = readLongsUnion("/tmp/AllIDs.txt",did);
long time = System.currentTimeMillis() - start;
System.out.println("Took "+ time+" ms to find "+ validIDS.size()+" valid ids");
}
private static TLongHashSet readLongs(String filename) throws IOException {
System.out.println("Reading ids in "+filename);
BufferedReader br = new BufferedReader(new FileReader(filename), 128*1024);
TLongHashSet ids = new TLongHashSet();
for(String line; (line = br.readLine())!=null;)
ids.add(Long.parseLong(line));
br.close();
return ids;
}
private static TLongHashSet readLongsUnion(String filename, TLongHashSet validSet) throws IOException {
System.out.println("Reading ids in "+filename);
BufferedReader br = new BufferedReader(new FileReader(filename), 128*1024);
TLongHashSet ids = new TLongHashSet();
for(String line; (line = br.readLine())!=null;) {
long val = Long.parseLong(line);
if (validSet.contains(val))
ids.add(val);
}
br.close();
return ids;
}
private static void generateFile(String filename, int number) throws IOException {
System.out.println("Generating "+number+" ids to "+filename);
PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(filename), 128*1024));
Random rand = new Random();
for(int i=0;i<number;i++)
pw.println(rand.nextInt(1<<26));
pw.close();
}
答案 1 :(得分:4)
170Mb + 14Mb并不是那么庞大的文件。
我的建议是将最小的一个文件加载到java.util.Map
,解析最大的一个逐行(逐个记录)文件,并检查此Map中是否存在当前行。
P.S。这个问题在RDBMS方面看起来像是微不足道的 - 也许它值得使用?
答案 2 :(得分:2)
当每次迭代太长时,你不能做O(N ^ 2),这是完全不可接受的。
如果你有足够的内存,你只需解析文件1,创建所有数字的地图,然后解析文件2并检查你的地图。
如果没有足够的RAM,请解析文件1,创建地图并将其存储到文件中,然后解析文件2并读取地图。关键是要使地图尽可能容易解析 - 使其成为二进制格式,可能使用二叉树或您可以快速跳过并搜索的内容。 (编辑:我必须添加Michael Borgwardt的Grace Hash Join链接,它显示了更好的方式:http://en.wikipedia.org/wiki/Hash_join#Grace_hash_join)
如果你的文件大小有限,选项1更容易实现 - 除非你正在处理huuuuuuuge文件(我说的是很多GB),你绝对想要这样做。
答案 3 :(得分:1)
通常,内存映射是读取大文件的最有效方法。你需要使用java.nio.MappedByteBuffer和java.io.RandomAccessFile。
但是你的搜索算法才是真正的问题。您需要构建某种索引或哈希表。