外排序(大文件内存不够无法一次加载)

简介: 对远远大于内存的数据进行外排序,在多路比较的时候用败者树效率会更高。这个算法可以在建立倒排索引的时候使用package my.sort;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.BufferedWriter;import java.io.Dat



对远远大于内存的数据进行外排序,在多路比较的时候用败者树效率会更高。

这个算法可以在建立倒排索引的时候使用



package my.sort;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Random;

/**
 * 基于大数据量的外排序算法,分为二路归并和多路归并
 * @author java2king
 * @link http://blog.csdn.net/Java2King
 *
 */
public class ExternalSort {

    public static int ITEM_COUNT = 10000000; //总数 

    public static int BUFFER_SIZE = 1024*4*1000;// 一次缓冲读取
    
    public static int FILE_COUNT = 1024*1000*1*4;// 每个文件的记录数
    
    public static File MAIN_FILE = new File("mainset");//要排序的文件

    /**
     * 二路归并
     * @param file
     * @return
     * @throws IOException
     */
    public File sort(File file) throws IOException {
        ArrayList<File> files = split(file);
        return process(files);
    }
    /**
     * 多路归并
     * @param file
     * @throws IOException
     */
    public void mSort(File file) throws IOException{
        ArrayList<File> files = split(file);
        multipleMerge(files);
        
    }

    // recursive method to merge the lists until we are left with a
    // single merged list
    private File process(ArrayList<File> list) throws IOException {
        if (list.size() == 1) {
            return list.get(0);
        }
        ArrayList<File> inter = new ArrayList<File>();
        for (Iterator<File> itr = list.iterator(); itr.hasNext();) {
            File one = itr.next();
            if (itr.hasNext()) {
                File two = itr.next();
                inter.add(merge(one, two));
            } else {
              //  return one;
                inter.add(one);
            }
        }
        return process(inter);
    }
    /**
     * Splits the original file into a number of sub files. 
     */
    private ArrayList<File> split(File file) throws IOException {
        ArrayList<File> files = new ArrayList<File>();
        int[] buffer = new int[FILE_COUNT];
        FileInputStream fr = new FileInputStream(file);
        BufferedInputStream bin = new BufferedInputStream(fr,BUFFER_SIZE);
        DataInputStream din=new DataInputStream(bin);  
        boolean fileComplete = false;
        
        while (!fileComplete) {
            int index = buffer.length;
            for (int i = 0; i < buffer.length && !fileComplete; i++) {
                try {
                     buffer[i] = din.readInt();
                } catch (Exception e) {
                    fileComplete = true;
                    index = i;
                }
            }
            if (index != 0 && buffer[0] > -1) {
                Arrays.sort(buffer, 0, index);
                File f = new File("set" + new Random().nextInt());
         //       File temp = File.createTempFile("josp", ".tmp", f);   
                FileOutputStream writer = new FileOutputStream(f);
                BufferedOutputStream bOutputStream = new BufferedOutputStream(writer);
             
                DataOutputStream dout=new DataOutputStream(bOutputStream); 
                for (int j = 0; j < index; j++) {
                    dout.writeInt(buffer[j]);
                }
                dout.close();
                bOutputStream.close();
                writer.close();
                files.add(f);
               
            }

        }
        din.close();
        bin.close();
        fr.close();
        return files;
    }
    /**
     * 多路归并
     * @param list
     * @throws IOException
     */
    private void multipleMerge(ArrayList<File> list) throws IOException {
        
        int fileSize = list.size();
        
        if(fileSize == 1){
            return;
        }
        
        ArrayList<DataInputStream> dinlist = new ArrayList<DataInputStream>();
        
        int[] ext = new int[fileSize];//比较数组

    //    File output = new File("multipleMerged");
        FileOutputStream os = new FileOutputStream(MAIN_FILE);
        BufferedOutputStream bout = new BufferedOutputStream(os);
        DataOutputStream dout = new DataOutputStream(bout);

        for (int i = 0; i < fileSize; i++) {
            try {
                dinlist.add(i, new DataInputStream(new BufferedInputStream(
                        new FileInputStream(list.get(i)), BUFFER_SIZE)));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        int index = 0;

        for (int i = 0; i < fileSize; i++) {
            try {
                ext[i] = dinlist.get(i).readInt();
            } catch (Exception e) {
                System.err.println("file_" + i + "为空");
                ext[i] = -1;
            }
        }
        int count = fileSize;
        int[] sum = new int[fileSize];
        
        while (count > 1) {

            index = getMinIndex(ext);
            dout.writeInt(ext[index]);
            sum[index]++;
            try {
                ext[index] = dinlist.get(index).readInt();
            } catch (Exception e) {
                ext[index] = -1;
                count--;
                dinlist.get(index).close();
        //        System.err.println(index + "空,写进:" +sum[index]);
                
            }
        }
        int sIndex = getSIndex(ext);
        dout.writeInt(ext[sIndex]);
        while (true) {
            try {
                dout.writeInt(dinlist.get(sIndex).readInt());
            } catch (Exception e) {
                dinlist.get(sIndex).close();
                break;
            }
        }
        dout.close();
    }
    //找到剩下的最后一个文件输入流
    public int getSIndex(int[] ext){
        int result = 0;
        for (int i = 0; i < ext.length; i++) {
            if(ext[i]!= -1){
                result = i;
                break;
            }
        }
        return result;
    }
    //找到数据中最小的一个
    public int getMinIndex(int[] ext){
        int min = 2147483647;
        int index = -1;
        for (int i = 0; i < ext.length; i++) {
            if(ext[i] != -1 && ext[i] < min){
                min = ext[i];
                index = i;
            }
        }
        return index;
    }
    /**
     * 二路归并
     * 
     * @param one
     * @param two
     * @return
     * @throws IOException
     */
    private File merge(File one, File two) throws IOException {
        FileInputStream fis1 = new FileInputStream(one);
        FileInputStream fis2 = new FileInputStream(two);
        BufferedInputStream bin1 = new BufferedInputStream(fis1,BUFFER_SIZE);
        BufferedInputStream bin2 = new BufferedInputStream(fis2,BUFFER_SIZE);
        
        DataInputStream din1=new DataInputStream(bin1);  
        DataInputStream din2=new DataInputStream(bin2);  
        
        File output = new File("merged" + new Random().nextInt());
        FileOutputStream os = new FileOutputStream(output);
        BufferedOutputStream bout = new BufferedOutputStream(os);
        DataOutputStream dout=new DataOutputStream(bout); 
   
        int a = -1;//= din1.readInt();
        int b = -1;//= din2.readInt();
        
        boolean finished = false;
        boolean emptyA = false;//
        int flag = 0;
        while (!finished) {

            if (flag != 1) {
                try {
                    a = din1.readInt();
                } catch (Exception e) {
                    emptyA = true;
                    break;
                }
            }
            if (flag != 2) {
                try {
                    b = din2.readInt();
                } catch (Exception e) {
                    emptyA = false;
                    break;
                }
            }
            if(a > b){
                dout.writeInt(b);
                flag = 1;
            }else if( a < b){
                dout.writeInt(a);
                flag = 2;
            }else if(a == b){
                dout.write(a);
                dout.write(b);
                flag = 0;
            }
        }
        finished = false;
        if(emptyA){
            dout.writeInt(b);
            while(!finished){
                try {
                    b = din2.readInt();
                } catch (Exception e) {
                    break;
                }
                dout.writeInt(b);
            }
        }else{
            dout.writeInt(a);
            while(!finished){
                try {
                    a = din1.readInt();
                } catch (Exception e) {
                    break;
                }
                dout.writeInt(a);
            }
        }
        dout.close();
        os.close();
        bin1.close();
        bin2.close();
        bout.close();
        return output;
    }

 

  

    /**
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
              
        Random random = new Random(System.currentTimeMillis());
        FileOutputStream fw = new FileOutputStream(MAIN_FILE);
        BufferedOutputStream bout = new BufferedOutputStream(fw);
        DataOutputStream dout=new DataOutputStream(bout);  
        
        for (int i = 0; i < ITEM_COUNT; i++) {
            int ger = random.nextInt();
            ger = ger < 0 ? -ger : ger;
            dout.writeInt(ger);

        }
        dout.close();
        bout.close();
        fw.close();
        ExternalSort sort = new ExternalSort();
        System.out.println("Original:");

        long start = System.currentTimeMillis();
        sort.mSort(MAIN_FILE);
       
        
        long end = System.currentTimeMillis();
        System.out.println((end - start)/1000 + "s");
        recordFile((end - start)/1000 ,true);
    }

    private static void recordFile(long time,boolean isBuffer)
            throws FileNotFoundException, IOException {
        BufferedWriter bw = new BufferedWriter(new FileWriter("log",true));
        bw.write("FILE_COUNT = "+FILE_COUNT+";对"+ ITEM_COUNT + "条数据 "+ ITEM_COUNT*4/(1024*1204) +"MB排序耗时:" + time + "s ");
        if(isBuffer){
            bw.write("  使用缓冲:"+BUFFER_SIZE*4/(1024*1204) +"MB");
        }
        bw.newLine();
        bw.close();
    }

}



另一篇采用新IO实现的

http://www.oschina.net/code/snippet_1386372_48711#70574


目录
相关文章
|
Unix 程序员 Linux
【OSTEP】动态内存开辟 | 内存API常见错误 | UNIX: brk/sbrk 系统调用 | mmap创建匿名映射区域 | mmap创建以文件为基础的映射区域
【OSTEP】动态内存开辟 | 内存API常见错误 | UNIX: brk/sbrk 系统调用 | mmap创建匿名映射区域 | mmap创建以文件为基础的映射区域
270 0
|
4月前
|
存储 Java 开发工具
【Azure 存储服务】Azure Blob上传大文件(600MB)出现内存溢出情况(Java SDK)
【Azure 存储服务】Azure Blob上传大文件(600MB)出现内存溢出情况(Java SDK)
|
2月前
|
缓存 监控 Java
在使用 Glide 加载 Gif 动画时避免内存泄漏的方法
【10月更文挑战第20天】在使用 Glide 加载 Gif 动画时,避免内存泄漏是非常重要的。通过及时取消加载请求、正确处理生命周期、使用弱引用、清理缓存和避免重复加载等方法,可以有效地避免内存泄漏问题。同时,定期进行监控和检测,确保应用的性能和稳定性。需要在实际开发中不断积累经验,根据具体情况灵活运用这些方法,以保障应用的良好运行。
|
2月前
|
数据处理 Python
如何优化Python读取大文件的内存占用与性能
如何优化Python读取大文件的内存占用与性能
179 0
|
2月前
|
数据处理 Python
Python读取大文件的“坑“与内存占用检测
Python读取大文件的“坑“与内存占用检测
66 0
|
2月前
|
Linux C++
Linux c/c++文件虚拟内存映射
这篇文章介绍了在Linux环境下,如何使用虚拟内存映射技术来提高文件读写的速度,并通过C/C++代码示例展示了文件映射的整个流程。
60 0
|
2月前
|
程序员 Windows
程序员必备文件搜索工具 Everything 带安装包!!! 比windows自带的文件搜索快几百倍!!! 超级好用的文件搜索工具,仅几兆,不占内存,打开即用
文章推荐了程序员必备的文件搜索工具Everything,并提供了安装包下载链接,强调其比Windows自带搜索快且占用内存少。
49 0
|
3月前
|
存储 安全 Linux
将文件映射到内存,像数组一样访问
将文件映射到内存,像数组一样访问
37 0
|
5月前
|
Java
jmap 查看jvm内存大小并进行dump文件内存分析
jmap 查看jvm内存大小并进行dump文件内存分析
120 3
|
7月前
|
存储 缓存 Java
释放C盘空间:释放Windows休眠文件和关闭虚拟内存
在 Windows 11 专业版中,可以通过以下步骤来释放休眠文件(Hibernate File),以释放磁盘空间。休眠文件是系统休眠(Hibernate)功能所需要的文件,它保存了系统的当前状态,以便在休眠状态下恢复。如果你不使用休眠功能,如果因为C盘空间不足,可以考虑释放这个文件来腾出磁盘空间。
17361 1