2015-11-04 167 views
5

我有一臺具有4 GB內存和10 GB內存使用率的文件。現在,我要檢查,如果該文件中的每一行都是唯一的,所以我寫了下面的代碼:如何提取4GB內存中大於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異常,所以我的問題是:
我應該如何改變我的代碼來獲得每行都是唯一的文件?
非常感謝您的幫助。

+0

拆分成塊並比較pairwaise。或者散列每一行,並將散列和行一起存儲。 – user

+0

散列問題是,每一行只是一個散列,我應該如何分塊我可能會錯過一些重複的行。 –

+0

看看RandomAccessFile,你可以從RandomAccessFile'a'中讀取第1行,並將其與RandomAccessFile'b'的所有其他行進行比較。之後讀取第2行等 – user

回答

0

你可以嘗試尋找重複的行散列首先確定潛在的重複線路:

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爲空,則不存在重複,如果不是,則可以對該文件執行第二遍以檢查這些行是否完全相同。

+1

使用Koloboke ['IntIntMap'](http://openhft.github.io/Koloboke/api/0.6/java7/net/openhft/koloboke/collect/map/IntIntMap.html)也會更具有內存效率)或Trove ['TIntIntHashMap'](http://trove4j.sourceforge.net/javadocs/gnu/trove/map/hash/TIntIntHashMap.html)來表示地圖。 –

+0

關於第二遍,如果切換到啓用隨機訪問的文件,則可以跳過它。然後,您可以向後滾動並查看每個可能重複的行。實際上,無論如何,第二次通過都是不可能的。 – bezmax

+0

@bezmax隨機訪問無法幫助你去行xyz - 你只能跳過一些字節 - 在我的例子中我可以存儲字節位置而不是行號。 – assylias

0

由於您的RAM內存,您無法以此方式執行該操作。相反,您可以讀取該文件並生成n個具有固定大小(f.e:10.000行)的文件,讀取一行並將其放入實際文件中。達到文件限制時,打開一個新文件釋放所有保存的內存對象,然後執行第二個循環,並使用字符串(對於行)將原始文件的每一行與生成的n個文件進行比較。也許這樣可以避免內存空白。

有點奇怪,並且會是一個緩慢的過程,但這樣我認爲你可以達到你的要求。

如果您需要密碼,請告訴我。

希望幫助

+0

你知道你不需要在內存中加載整個文件來處理它,不是嗎? – Marco

-1

你可以用這樣的欺騙:(例子是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哈希值可能會使您對線的唯一性有更多的確定性。

+1

由於散列衝突,這不起作用。 – bezmax

+0

它應該檢測到散列衝突,因爲他想要一個只有唯一行的文件。讓我猜猜,你是那個低估了這個不是你的人...... –

相關問題