教新手使用java如何對一個大的文本文件內(nèi)容進(jìn)行去重
更新時間:2021年06月22日 11:19:47 作者:wei503316325
用HashSet對內(nèi)容去重這個過程jvm會內(nèi)存溢出,只能首先將這個大文件中的內(nèi)容讀取出來,對每行String的hashCode取模取正整數(shù),可用取模結(jié)果作為文件名,將相同模數(shù)的行寫入同一個文件,再單獨(dú)對每個小文件進(jìn)行去重,最后再合并
有內(nèi)存溢出風(fēng)險的寫法:
public static void distinct() { File ff = new File("G://password/all.txt"); File distinctedFile = new File("G://password/all-distinced.txt"); PrintWriter pw = null; Set<String> allHash = null; FileReader fr = null; BufferedReader br = null; try { pw = new PrintWriter(distinctedFile); allHash = new HashSet<String>(); fr = new FileReader(ff); br = new BufferedReader(fr); String line = null; while((line=br.readLine())!=null){ line = line.trim(); if(line != ""){ allHash.add(line); } } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if(null != fr){ fr.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(null != br){ br.close(); } } catch (IOException e) { e.printStackTrace(); } } for(String s:allHash){ pw.println(s); } pw.close(); }
jvm內(nèi)存溢出:
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded at java.util.HashMap.newNode(HashMap.java:1734) at java.util.HashMap.putVal(HashMap.java:630) at java.util.HashMap.put(HashMap.java:611) at java.util.HashSet.add(HashSet.java:219) at encode.Main.distinct(Main.java:180) at encode.Main.main(Main.java:215)
通過hashCode取模拆分寫法:
import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.util.HashSet; import java.util.Set; public class DistinctFileUtil { /** * 將文件hash取模之后放到不同的小文件中 * @param targetFile 要去重的文件路徑 * @param splitSize 將目標(biāo)文件切割成多少份hash取模的小文件個數(shù) * @return */ public static File[] splitFile(String targetFile,int splitSize){ File file = new File(targetFile); BufferedReader reader = null; PrintWriter[] pws = new PrintWriter[splitSize]; File[] littleFiles = new File[splitSize]; String parentPath = file.getParent(); File tempFolder = new File(parentPath + File.separator + "test"); if(!tempFolder.exists()){ tempFolder.mkdir(); } for(int i=0;i<splitSize;i++){ littleFiles[i] = new File(tempFolder.getAbsolutePath() + File.separator + i + ".txt"); if(littleFiles[i].exists()){ littleFiles[i].delete(); } try { pws[i] = new PrintWriter(littleFiles[i]); } catch (FileNotFoundException e) { e.printStackTrace(); } } try { reader = new BufferedReader(new FileReader(file)); String tempString = null; while ((tempString = reader.readLine()) != null) { tempString = tempString.trim(); if(tempString != ""){ //關(guān)鍵是將每行數(shù)據(jù)hash取模之后放到對應(yīng)取模值的文件中,確保hash值相同的字符串都在同一個文件里面 int index = Math.abs(tempString.hashCode() % splitSize); pws[index].println(tempString); } } } catch (Exception e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e1) { e1.printStackTrace(); } } for(int i=0;i<splitSize;i++){ if(pws[i] != null){ pws[i].close(); } } } return littleFiles; } /** * 對小文件進(jìn)行去重合并 * @param littleFiles 切割之后的小文件數(shù)組 * @param distinctFilePath 去重之后的文件路徑 * @param splitSize 小文件大小 */ public static void distinct(File[] littleFiles,String distinctFilePath,int splitSize){ File distinctedFile = new File(distinctFilePath); FileReader[] frs = new FileReader[splitSize]; BufferedReader[] brs = new BufferedReader[splitSize]; PrintWriter pw = null; try { if(distinctedFile.exists()){ distinctedFile.delete(); } distinctedFile.createNewFile(); pw = new PrintWriter(distinctedFile); Set<String> unicSet = new HashSet<String>(); for(int i=0;i<splitSize;i++){ if(littleFiles[i].exists()){ System.out.println("開始對小文件:" + littleFiles[i].getName() + "去重"); frs[i] = new FileReader(littleFiles[i]); brs[i] = new BufferedReader(frs[i]); String line = null; while((line = brs[i].readLine())!=null){ if(line != ""){ unicSet.add(line); } } for(String s:unicSet){ pw.println(s); } unicSet.clear(); System.gc(); } } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e1){ e1.printStackTrace(); } finally { for(int i=0;i<splitSize;i++){ try { if(null != brs[i]){ brs[i].close(); } if(null != frs[i]){ frs[i].close(); } } catch (IOException e) { e.printStackTrace(); } //合并完成之后刪除臨時小文件 if(littleFiles[i].exists()){ littleFiles[i].delete(); } } if(null != pw){ pw.close(); } } } public static void main(String[] args) throws IOException { int splitSize = 20; File[] files = splitFile("G://test/bigfile.txt",splitSize); distinct(files,"G://test/bigfile-distinct.txt",splitSize); } }
總結(jié)
本篇文章的內(nèi)容就到這了,希望大家可以喜歡,也希望大家可以多多關(guān)注腳本之家的其他精彩內(nèi)容!
相關(guān)文章
MyBatis注解方式之@Update/@Delete使用詳解
這篇文章主要介紹了MyBatis注解方式之@Update/@Delete使用詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11java使用spring實(shí)現(xiàn)讀寫分離的示例代碼
本篇文章主要介紹了java使用spring實(shí)現(xiàn)讀寫分離的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-12-12JavaWeb請求轉(zhuǎn)發(fā)和請求包含實(shí)現(xiàn)過程解析
這篇文章主要介紹了JavaWeb請求轉(zhuǎn)發(fā)和請求包含實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-02-02Spring/SpringBoot?@RequestParam注解無法讀取application/json格式數(shù)據(jù)問題
RequestParam用于將指定的請求參數(shù)賦值給方法中的形參,可以接受簡單類型屬性,也可以接受對象類型,一般用于GET請求,下面這篇文章主要給大家介紹了關(guān)于Spring/SpringBoot?@RequestParam注解無法讀取application/json格式數(shù)據(jù)問題解決的相關(guān)資料,需要的朋友可以參考下2022-10-10