`
royzhou1985
  • 浏览: 254437 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Java 大文件读取排序

    博客分类:
  • Java
阅读更多
需求:
csv文件中存在千万级数据,需要按照某一列进行排序
比如
1,royzhou1985@163.com,13752468532,123,1
1,royzhou1985@183.com,13752465532,123,1
1,royzhou1985@173.com,13752463532,123,1

要求可以按照其中某一列,比如邮件地址或者手机号码排序。

实现:
为了不导致内存溢出,每次读取一定数量的记录,比如10W行记录。使用Java API Collections.sort()排序,然后写到一个临时文件。 这样就可以将大文件拆分成很多个排序了的小文件.

然后打开这些小文件,全部读取一行,获取最小的值,然后从那个文件再读取一行,循环判断直到所有文件读取结束。

问题:
性能较差,合成大文件的时候需要做很多次比较。

改进:
分割文件可以用多线程,讲读取到的10W行记录在线程中排序处理。
合成文件?

代码实现:
package com.royzhou.sort;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import com.roy.zhou.util.SysConfig;

public class FileSorter {
	
	public int sort(String fileName, LineProcessor lineProcessor) throws InterruptedException, IOException {
		int index = split(fileName, lineProcessor);
		int totalCount = merge(fileName, index, lineProcessor);
		return totalCount;
	}
	
	public int split(String fileName, LineProcessor lineProcessor) throws InterruptedException, IOException {
		int fileIndex = 0;
		BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>();
		ThreadPoolExecutor pool = new ThreadPoolExecutor(SysConfig.THREAD_NUMBER, SysConfig.THREAD_NUMBER, 600, TimeUnit.SECONDS, workQueue);
		BufferedReader br = null;
		int row = 0;
		String sLine = null;
		String sKey = null;
		List<SortedData> sList = new ArrayList<SortedData>();
		//LineProcessor lineProcessor = new CSVLineProcessor(SysConfig.KEY_INDEX);
		br = new BufferedReader(new InputStreamReader(new FileInputStream(fileName)));
		while((sLine=br.readLine())!=null) {
			sKey = lineProcessor.process(sLine);
			sList.add(new SortedData(sKey, sLine, br));
			row++;
			
			if(row!=0 && row%SysConfig.BATCH_ROW_COUNT==0) {
				new FileSplitController(pool, workQueue, sList, fileName, fileIndex).dispatchTask();
				sList = new ArrayList<SortedData>();
				fileIndex++;
			}
		}
		/**
		 * check whether there is still records to be processed
		 */
		if(sList.size()>0) {
			new FileSplitController(pool, workQueue, sList, fileName, fileIndex).dispatchTask();
			fileIndex++;
		}
		while(workQueue.size()>1) {
			Thread.sleep(5000);
		}
		pool.shutdown();
		/**
		 * if all task still not finish, sleep 5 seconds and check again
		 */
		while(!pool.isTerminated()) {
			pool.awaitTermination(5, TimeUnit.SECONDS);
		}
		return fileIndex;
	}
	
	public int merge(String fileName, int index, LineProcessor lineProcessor) throws IOException {
		int totalCount = 0;
		BufferedWriter bw = null;
		BufferedReader[] fileReaders = new BufferedReader[index];
		List<SortedData> sortedDatas = new ArrayList<SortedData>(index);
		File[] tempFiles = new File[index];
		String iFilePath = null;
		String outputFile = null;
		String sLine = null;
		String sKey = null;
		for(int i=0; i<index; i++) {
			iFilePath = fileName + ".tmp" + i;
			tempFiles[i] = new File(iFilePath);
			fileReaders[i] = new BufferedReader(new InputStreamReader(new FileInputStream(iFilePath)));
			sLine = fileReaders[i].readLine();
			sKey = lineProcessor.process(sLine);
			sortedDatas.add(new SortedData(sKey, sLine, fileReaders[i]));
		}
		
		outputFile = fileName + ".sorted";
		bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFile)));
		
		SortedData smallestData = null;
		String smallestKey = null;
		String smallestContent = null;
		String tempKey = null;
		String tempContent = null;
		BufferedReader tempReader = null;
		while(true) {
			Collections.sort(sortedDatas);
			smallestData = sortedDatas.get(0);
			smallestKey = smallestData.getKey();
			if(smallestKey==null || "".equals(smallestKey)) {
				break;
			}
			smallestContent = smallestData.getContent();
			tempReader = smallestData.getFileReader();
			bw.write(smallestContent + "\n");
			totalCount++;
			tempContent = tempReader.readLine();
			tempKey = lineProcessor.process(tempContent);
			sortedDatas.set(0, new SortedData(tempKey, tempContent, tempReader));
		}
		
		bw.flush();
		bw.close();
		
		for(int i=0; i<index; i++) {
			fileReaders[i].close();
			tempFiles[i].delete();
		}
		System.out.println(totalCount);
		return totalCount;
	}
}


分享到:
评论
2 楼 jidacwj 2014-04-13  
楼主写的这个有问题呀
首先,多线程分割文件第45行,我尝试打印每个线程的启动与结束时间,结果并不是并行执行的:
线程0开始时间:2014-04-13  22:08:05
耗时:1min0s640ms
线程0结束时间:2014-04-13  22:09:06
线程1开始时间:2014-04-13  22:09:06
耗时:46s632ms
线程1结束时间:2014-04-13  22:09:52
2线程,总耗时:耗时:1min47s518ms
这是为什么呢???!
另外有个建议:
第100行,没必要每次都进行排序,对100000条排序也挺费时间的。只要遍历一遍,找出最小的那条就行。速度能快一倍多。
1 楼 caidezhi655 2012-03-26  
茫茫互联网,这样都能搜到你的博客

相关推荐

    java 大文件 多字段排序

    在Java编程中,处理大文件并进行多字段排序是一项挑战性的任务,特别是在内存有限的情况下。以下将详细讲解如何实现这个目标。 首先,我们要理解大文件排序的基本原理。当文件太大无法一次性加载到内存时,我们需要...

    Java读取文件并对其排序后重新写入文件

    在Java编程中,读取文件、对数据进行排序并重新写入文件是常见的操作,尤其在数据处理和分析场景中。下面将详细讲解这个过程,包括相关知识点和具体实现。 首先,我们需要导入Java的`java.io`包,该包包含了处理...

    java文件夹按时间、大小等排序

    在Java编程中,对文件夹中的文件进行排序是一项常见的任务,尤其在处理大量数据或进行自动化操作时。这里我们将深入探讨如何使用Java实现文件按时间、大小等属性进行排序的功能。 首先,我们要引入`java.io.File`类...

    java对大数据量文件内容的多线程读取和排序.pdf

    Java 对大数据量文件内容的多线程读取和排序 在处理大数据量文件内容时,多线程读取和排序是非常重要的。下面我们将讨论如何使用 Java 对大数据量文件内容进行多线程读取和排序。 首先,我们需要生成一个随机的...

    java对大数据量文件内容的多线程读取和排序.doc

    Java 对大数据量文件内容的多线程读取和排序是非常复杂的任务,涉及到多个方面的技术,包括文件读取、多线程处理、排序算法等。本文将对该问题进行详细的分析和解决方案。 问题描述 生成一个随机的文本文件,其中...

    javaGUI成绩录入和排序文件读取

    Java GUI成绩录入与排序文件读取是一个典型的桌面应用程序开发示例,主要涉及到Java Swing或JavaFX库用于构建图形用户界面,以及文件I/O操作来处理数据的存储和检索。在这个项目中,用户可以通过一个简单的界面输入...

    JAVA设计文本文件读取倒序排序

    这个名为"JAVA设计文本文件读取倒序排序"的项目,利用NetBeans IDE,实现了读取文本文件内容并进行倒序排序的功能,同时也提供了保存处理结果的能力。在这个过程中,涉及到的关键知识点包括: 1. **Java I/O流**:...

    java对大数据量文件内容的多线程读取和排序.zip_大数据 java_文件读取

    本文将详细介绍如何在Java中实现对大数据量文件内容的多线程读取和排序。 首先,理解多线程的概念是至关重要的。线程是程序执行的最小单元,每个线程都有自己的程序计数器、虚拟机栈、本地方法栈和一部分堆内存。...

    java读取文件内容

    在Java中,文件读取是通过`java.io`包中的类来实现的。本例中用到了`BufferedReader`和`FileReader`。 - **BufferedReader**:提供了一个方便的接口用于读取文本文件中的字符数据。它具有从输入流中读取文本的功能...

    java 把大文件分割为小文件

    这是通过使用 FileReader 和 BufferedReader 读取大文件,然后将其写入到多个小文件中实现的。 ### 2. 文件写入 文件写入是指将数据写入到文件中。在 Java 中,可以使用 Java.IO 包中的 FileWriter 和 ...

    java集合排序及文件读取.rar

    在"java集合排序及文件读取.rar"这个压缩包中,我们很可能会找到关于如何在Java中对集合进行排序以及如何读取文件的示例代码。让我们详细探讨这些关键知识点。 **Java集合排序** Java集合框架包括接口如`List`、`...

    java 大文件ip 统计

    综上所述,Java大文件IP统计涉及的主要知识点有:Java文件I/O,流式处理,IP地址的处理与比较,数据结构(如HashMap和TreeMap)的选择,以及可能的并发和分布式计算。通过这些技术,我们可以高效地处理大文件中的IP...

    Java实现外部排序(10M内存排序1G大文件)

    有文件大小为1G的一个文件,文件每行存储的为URL及其访问次数,例如/api/auth/login 2 ,计算出访问次数最多的前5个URL和其访问次数,每行的URL可能重复,计算内存限制10M。 === 内含解题思路、测试结果截图、可运行...

    Java写入大数据文件

    sqlitFileDate方法使用FileReader和BufferedReader来读取大数据文件,并使用LinkedList来存储文件流对象和BufferedWriter对象,然后将每个小文件的数据写入到对应的文件中。 在写入和切分文件操作完成后,程序使用...

    java进阶(文件读写、递归、数组排序、单体工厂模式)

    本课程着重讲解了四个核心概念:文件读写、递归、数组排序以及单体工厂模式。这些知识点都是Java开发者日常工作中不可或缺的部分。 首先,我们来探讨文件读写。在Java中,文件操作主要依赖于I/O(Input/Output)流...

    文件读出数组进行选择排序和二分查找(java)

    在Java编程中,文件读取、数组操作、选择排序以及二分查找是常见的编程任务,它们涉及了IO流、数据结构和算法等多个方面。以下是这些知识点的详细解释: 1. **文件读取**:Java提供了丰富的IO流类库用于读取文件。...

    java读取txt文件代码

    此段代码展示了基本的文件读取过程,但是原文件中的部分代码似乎尝试进行更复杂的数据处理,包括数据解析、计算和排序。这部分代码涉及到了数据的结构化存储(如使用`List`和`Map`),以及数学运算和排序算法。 ###...

    读取文件数字并排序最后输出另一个文件

    读取一个文件中的整数,并将它们从小到大排序,最后输出排序后到另一个文件中

    java归并外排序

    在实际应用中,Java归并外排序适用于大数据处理场景,如大数据分析、数据库索引构建等。由于其稳定性和效率,尤其是在处理无法一次性加载到内存的数据集时,归并外排序是理想的选择。 总结起来,Java归并外排序是...

Global site tag (gtag.js) - Google Analytics