`

找出两个大文件中数据不同部分

阅读更多

如何找出两个大文件中的数据不同部分

问题描述:对比两个大于4G的日志文件A和B,如何高效的找出A和B中的数据不同部分。

整体思路:

第一步:文件分割;将大文件分割成多个小文件。本文采用哈希函数来分割大文件,扫描文件A,对每行字符求hash(url) % M,url是文件中的一行字符串,本文中的hash函数取JDK自带的hashCode方法,M表示分解的文件数目。根据所得的值,将url写入到对应的小文件中,如hash(url) % M = 4,则写入第四个文件中。如此,大文件A可以分为<a(0),a(1),a(2),...a(M-1)>,同理,大文件B可以分为<b(0),b(1),...b(M-1)>。可能相同的url必然都在对应的小文件中,也就是说,我们只需要寻找对应的小文件中的不同部分,然后归并所有的不同部分就是整个两个大文件的数据不同部分。

第二步:证明:可能相同的url必然都在对应的小文件中

假设X为文件A中的某行字符串,Y为文件B中的某行字符串,X.equals(Y) == true,则hash(X) == hash(Y), hash(X) % M == hash(Y) % M,则令k = hash(X) % M,则X必然在a(k)中,Y必然在b(k)中。

第三步:hash统计。统计小文件a(i)和b(i)中的不同部分,最后归并。代码如下:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

public class TestBigData {

	// 分割的文件数
	private static final int CUTTED_FILE_NUM = 30;
	//文件后缀名
	private static final String FILE_EXTENSIONS = ".log";
	//回车换行
	private static final String NEWLINE ="\r\n";

	/**
	 * 输入大文件的路径,根据Hash函数讲大文件分割成若干个小文件
	 * 
	 * @param sourceFilePath
	 * @param destinationFilePath
	 */
	public static void hashCutFile(String sourceFilePath,
			String destinationDirPath) {
		File fr = new File(sourceFilePath);
		BufferedReader br = null;
		BufferedWriter bw = null;
		String[] filePath = new String[CUTTED_FILE_NUM];
		for (int i = 0; i < filePath.length; i++) {
			filePath[i] = destinationDirPath + i + FILE_EXTENSIONS;
		}

		String[] split = new String[2];
		try {
			br = new BufferedReader(new FileReader(fr));
			String line = br.readLine();
			while (line != null) {
				// 数据格式为00001016114116820131725061748117041361&4580337030|||112050
				// 规范化数据
				split = line.split("\\|\\|\\|");
				String url = split[0];
				// 采用字符串自带的hashCode作为Hash函数
				int hashcode = new Integer(url.hashCode());
				int hashResult = hashcode % CUTTED_FILE_NUM;
				if (hashResult < 0) {
					hashResult = hashResult + CUTTED_FILE_NUM;
				}
				bw = new BufferedWriter(new FileWriter(new File(
						filePath[hashResult]), true));
				bw.write(url);
				bw.write(NEWLINE);
				bw.close();
				line = br.readLine();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				br.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}

	/**
	 * 查找两个文件中不同的内容
	 * 
	 * @param fileA
	 * @param fileB
	 */
	public static List<String> findDifference(String fileA, String fileB) {
		List<String> partialResult = new ArrayList<String>();
		File frA = new File(fileA);
		File frB = new File(fileB);
		BufferedReader brA = null;
		BufferedReader brB = null;
		List<String> listA = new ArrayList<String>();
		List<String> listB = new ArrayList<String>();
		Set<String> hashset = new HashSet<String>();
		try {
			brA = new BufferedReader(new FileReader(frA));
			brB = new BufferedReader(new FileReader(frB));
			// 把fileA的内容读入到listA中
			String line = brA.readLine();
			while (line != null) {
				listA.add(line);
				line = brA.readLine();
			}

			line = null;
			// 把fileB的内容读入到listB中
			line = brB.readLine();
			while (line != null) {
				listB.add(line);
				line = brB.readLine();
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				brA.close();
				brB.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		hashset.addAll(listB);
		for (int i = 0; i < listA.size(); i++) {
			String elemA = listA.get(i);
			if (!hashset.contains(elemA)) {
				partialResult.add(elemA);
			}
		}
		hashset.clear();
		hashset.addAll(listA);
		for (int i = 0; i < listB.size(); i++) {
			String elemB = listB.get(i);
			if (!hashset.contains(elemB)) {
				partialResult.add(elemB);
			}
		}

		return partialResult;
	}
	
	/**
	 * 
	 * @param file
	 * @return
	 */
	public static List<String> findDifference(String file) {
		List<String> partialResult = new ArrayList<String>();
		File fr = new File(file);
		BufferedReader br = null;
		try {
			br = new BufferedReader(new FileReader(fr));
			// 把file的内容读入到list中
			String line = br.readLine();
			while (line != null) {
				partialResult.add(line);
				line = br.readLine();
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				br.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return partialResult;
	}

	/**
	 * list1和list2求交集
	 * 
	 * @param list1
	 * @param list2
	 * @return
	 */
	public static List<String> Intersection(List<String> list1,
			List<String> list2) {
		List<String> list = new ArrayList<String>();
		Set<String> hashSet = new HashSet<String>();
		hashSet.addAll(list2);
		for (int i = 0; i < list1.size(); i++) {
			String temp = list1.get(i);
			if (hashSet.contains(list1.get(i))) {
				list.add(temp);
			}
		}
		return list;
	}

	/**
	 * 求List1与List2的差集 list1 - list2
	 * 
	 * @param list1
	 * @param list2
	 * @return
	 */
	public static List<String> Complement(List<String> list1, List<String> list2) {
		List<String> list = new ArrayList<String>();
		Set<String> hashSet = new HashSet<String>();
		hashSet.addAll(list2);
		for (int i = 0; i < list1.size(); i++) {
			String temp = list1.get(i);
			if (!hashSet.contains(temp)) {
				list.add(temp);
			}
		}
		return list;
	}

	/**
	 * 归并所有小文件中所有不相同的内容
	 * 
	 * @param dirAPath
	 *            大文件A对应的分割后的小文件目录
	 * @param dirBPath
	 *            大文件B对应的分割后的小文件目录
	 * @return
	 */
	public static Set<String> mergeDifferenceList(String dirAPath,
			String dirBPath) {
		Set<String> resultSet = new HashSet<String>();
		File dirA = new File(dirAPath);
		File dirB = new File(dirBPath);
		File[] Afiles = dirA.listFiles();
		File[] Bfiles = dirB.listFiles();
		String Afiletemp = dirA.getAbsolutePath();
		String Bfiletemp = dirB.getAbsolutePath();
		List<String> AfilesPath = new ArrayList<String>();
		List<String> BfilesPath = new ArrayList<String>();
		//存放A和B的交集结果
		List<String> intersectionList = new ArrayList<String>();
		//存放A - A与B的交集
		List<String> complementListA = new ArrayList<String>();
		//存放B - A与B的交集
		List<String> complementListB = new ArrayList<String>();
		for (int i = 0; i < Afiles.length; i++) {
			AfilesPath.add(Afiles[i].getName());
		}
		for (int i = 0; i < Bfiles.length; i++) {
			BfilesPath.add(Bfiles[i].getName());
		}
		intersectionList = Intersection(AfilesPath, BfilesPath);
		for (int i = 0; i < intersectionList.size(); i++) {
			resultSet.addAll(findDifference(Afiletemp + "\\" + intersectionList.get(i), Bfiletemp
							+ "\\" + intersectionList.get(i)));
		}

		complementListA = Complement(AfilesPath, intersectionList);
		complementListB = Complement(BfilesPath, intersectionList);
		for (int i = 0; i < complementListA.size(); i++) {
			resultSet.addAll(findDifference(Afiletemp + "\\"
					+ complementListA.get(i)));
		}

		for (int i = 0; i < complementListB.size(); i++) {
			resultSet.addAll(findDifference(Bfiletemp + "\\"
					+ complementListB.get(i)));
		}
		return resultSet;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		long t1 = System.currentTimeMillis();
		String fileA = "C:/Users/jim/Desktop/big data/sourceFile1.log";
		String fileB = "C:/Users/jim/Desktop/big data/sourceFile2.log";
	//	String fileA = "C:/Users/jim/Desktop/big data/新建文本文档.txt";
	//	String fileB = "C:/Users/jim/Desktop/big data/新建文本文档 (2).txt";
		String destinationA = "C:/Users/jim/Desktop/big data/destinationA/";
		String destinationB = "C:/Users/jim/Desktop/big data/destinationB/";
		Set<String> hashset = new HashSet<String>();
		hashCutFile(fileA, destinationA);
		hashCutFile(fileB, destinationB);
		hashset = mergeDifferenceList(destinationA, destinationB);
		for (Iterator<String> it = hashset.iterator(); it.hasNext();) {
			System.out.println(it.next());
		}
		long t2 = System.currentTimeMillis();
		System.out.println("时间t= " + (t2 - t1) + "ms");
	}
}

 

分享到:
评论

相关推荐

    python筛选出两个文件中重复行的方法

    本文将详细介绍一个Python脚本,该脚本采用了一种高效的方法来筛选出两个文件中的重复行。 首先,我们需要理解脚本的基本思路。它分为两个主要步骤: 1. **拆分大文件**: 脚本首先打开第二个文件(B文件),并将...

    比较两个文件的不同 的代码

    它会标识出两个文件中的差异位置,帮助用户快速识别出哪些部分发生了改变。在Visual Studio 2005这样的集成开发环境中(IDE),这一功能已经内置,使得开发者可以方便地比较源代码文件的差异。 在Visual Studio ...

    比较两个文件夹文件的不同.rar

    1. **文件和文件夹比较**:在计算机科学中,比较两个文件夹的内容是为了找出它们之间的差异,例如独有的文件、同名但内容不同的文件以及完全相同的文件。这在版本控制、备份验证、同步操作等场景中非常常见。比较...

    文件比较,可以比较两个文件的不同地方

    文件比较,也称为文件差异分析或差异检测,是找出两个或多个文件之间内容差异的过程。这种技术广泛应用于各种领域,如编程、文档编辑、数据分析等。通过比较文件,我们可以快速定位到两个文件的修改之处,这在协同...

    可以对两个数据列一致的EXCEL文件进行快速比较。

    在数据分析、审计或者数据清理工作中,这样的功能非常实用,能够帮助用户快速找出两个工作表或列之间的差异,节省大量手动比对的时间。 描述中提到的“更新了算法,真正的高速比较”,暗示这个工具采用了优化的算法...

    两个 文本文件 逐行比较 文件内容 找出独有文本行

    用户只需提供两个文件路径,程序就能自动找出并加入独有的文本行。使用这样的工具可以大大简化操作,提高效率,尤其是对于非程序员来说。 总的来说,比较文本文件并找出独有行是文本处理中的常见需求,通过编程或...

    JAVA两个文件比较

    在日常的软件开发与维护工作中,经常需要对两个文件进行比较以检查它们之间的差异或一致性。在Java编程语言中,可以通过多种方式实现这一功能,例如利用字符流`BufferedReader`逐行读取并比较,或者采用字节流`...

    hadoop2面试题 - 迅速在两个含有大量数据的文件中寻找相同的数据.pdf

    hadoop2面试题 - 迅速在两个含有大量数据的文件中寻找相同的数据.pdf

    compdbf(比较任意两个dbf数据库之间的结构和数据差异).rar

    它能够快速、准确地检测出两个dbf文件之间的字段定义、记录数量、记录内容等方面的异同,对于数据库维护、数据迁移、数据校验等工作具有显著的辅助作用。 二、compdbf功能解析 1. 结构对比:compdbf能比较两个dbf...

    C# 两个datatable中的数据快速比较返回交集 并集或差集

    当我们处理多个DataTable时,可能需要比较它们之间的数据,找出交集、并集或差集。这在数据分析、数据清洗或者数据库同步等场景中非常常见。本教程将通过一个完整的源码示例,帮助初学者理解如何在C#中快速地完成这...

    绝好的两个文件夹下面文件差异的比较软件

    在IT领域,有时候我们需要对比两个文件夹中的内容,找出它们之间的差异,以便进行版本控制、数据同步或问题排查。在这种情况下,"绝好的两个文件夹下面文件差异的比较软件" 提供了一个高效的解决方案。虽然软件是...

    大文件JSON数据格式化工具与修改前后对比方法 迅速找出不同改动点

    描述中提到的“迅速找出不同改动点”,指的是比较两个或多个JSON文件之间的差异。这种功能在版本控制、协同开发或者数据校验中非常实用。本地编辑器对比工具有以下优势: 1. **高效性**:由于运行在本地,不受网络...

    把二进制文件中的数据读出,并写入到一个txt文件中去

    它接受两个参数:一个缓冲区(如`char`数组)和要读取的字节数。 ```cpp char buffer[BUFFER_SIZE]; inputFile.read(buffer, BUFFER_SIZE); ``` 4. **处理读取的数据**: 一旦数据被读取,你可以根据需求对...

    lua程序实现对两个文件的表的比较

    本文将深入探讨如何使用Lua来实现对两个文件中表的比较,找出它们之间的差异。 首先,我们需要理解Lua中的表。表是Lua的核心数据结构,它是一个动态大小的关联数组,可以存储任意类型的值,包括数字、字符串、其他...

    java实现找出两个文件中相同的单词(两种方法)

    描述部分“主要介绍了Java实现找出两个文件中相同的单词(两种方法),需要的朋友可以参考下”表明本篇文章的主要内容是介绍Java语言中实现找出两个文件中相同的单词的方法,并提供了两种不同的实现方式,以便需要...

    VC++ 操作EXCEL 比对两个EXCEL中的相同行 找出不同的元素

    本文将深入探讨如何使用VC++这一经典的C++集成开发环境(IDE)来操作Excel并实现两个文件中相同行的比对,找出其中的不同元素。 首先,VC++本身并不直接支持对Excel的操作,但可以通过Microsoft提供的库,如...

    两个Access文件中的表进行比较例程

    Access文件(.mdb或.accdb)存储了各种表、查询、报告等数据和对象,有时我们需要比较不同Access文件中的表,以确保数据的一致性或者找出差异。标题“两个Access文件中的表进行比较例程”揭示了这一具体需求,而描述...

    给出两个以行为单位文本文件的差集的命令行工具

    给出两个以行为单位文本文件的差集的命令行工具。 功能为输出当前目录下在文本文件prog中且不在文本文件list中的行。 可以用重定向将结果输出到文件中,比如: lackof &gt;result 注意文件无后缀名 比如文件prog中有4行...

    【GIS实战应用案例】利用ArcGIS提取重叠面部分教程.zip

    提取重叠面部分通常是为了分析两个或多个地理覆盖层之间的相互关系,例如,识别不同土地利用类型、行政区域或者自然保护区的交集。这种操作在环境规划、城市规划、灾害管理等多个领域都有广泛应用。 在ArcGIS中,...

    两个foxpro的dbf表的比较

    3. **SQL查询**:如果FoxPro支持SQL,可以使用`JOIN`或`EXCEPT`等SQL语句来找出两个表之间的差异。 4. **编程库或API**:对于更复杂的比较任务,可以利用FoxPro的编程库或API,创建自定义的比较算法。 在提供的...

Global site tag (gtag.js) - Google Analytics