使用java如何对一个大的文本文件内容进行去重

前言

今天从cdlinux论坛中下载了一份密码字典,纯txt文本文件,一个密码一行,加起来有1.5亿行,2G+,但是我怀疑里面有重复的密码,所以想对文件内容进行去重处理。

分析

一般可能会想到一次将文本内容读取到内存中,用HashSet对内容去重,但是很不幸这个过程jvm会内存溢出,无奈,只能另想办法,首先将这个大文件中的内容读取出来,对每行String的hashCode取模取正整数,可用取模结果作为文件名,将相同模数的行写入同一个文件,再单独对每个小文件进行去重,最后再合并。

有内存溢出风险的写法:

	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 allHash = null;
		FileReader fr = null;
		BufferedReader br = null;
		try {
			pw = new PrintWriter(distinctedFile);
			allHash = new HashSet();
			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内存溢出:

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 将目标文件切割成多少份hash取模的小文件个数
	 * @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 unicSet = new HashSet();
			for(int i=0;i

你可能感兴趣的:(java)