讀取海量資料到檔案並拆分排序

eff666發表於2016-09-04

1、從mysql讀取海量資料,將其寫入到檔案中,並拆分檔案進行排序。下面是測試用例。程式碼展示:

/**
 * Created by xxx on 2016/8/29.
 */

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Random;

public class CombinationSortWrite {
    /**
     * 大資料排序合併
     * 從msql資料庫讀取資料,寫入檔案,並將檔案拆分
     */
    public static void main(String[] args) throws IOException {
        // 寫入檔案的路徑
        String filePath = "D:\\456";
        // 切分檔案的路徑
        String sqlitFilePath = "D:\\456\\123";

        //資料的個數
        int CountNumbers = 1000000;

        //子檔案的個數
        int CountFile = 10;

        //精度
        int countAccuracy = 30*CountFile;

        long startNumber=System.currentTimeMillis();
        // 寫入大資料檔案
        WriteData(filePath,CountNumbers);
        System.out.println("儲存完畢");

        // 將大資料檔案切分到另外的十個小檔案中
        sqlitFileDate(filePath, sqlitFilePath,CountFile);
        System.out.println("檔案切割完畢!");

        // 把每個檔案的資料進行排序
        singleFileDataSort(sqlitFilePath,CountFile);
        System.out.println("每個子檔案排序完畢!");

        //精度調整,十個檔案資料進行比較整合
        deathDataFile(filePath,sqlitFilePath,countAccuracy,CountFile);
        System.out.println("整合完畢");
        long stopNumber=System.currentTimeMillis();
        System.out.println("耗時"+(stopNumber-startNumber)/1000+"毫秒");
    }

    // 寫入大資料檔案
    public static void WriteData(String path,int CountNumbers) throws IOException {
        path = path + "\\12114.txt";
        FileWriter fs = new FileWriter(path);
        BufferedWriter fw = new BufferedWriter(fs);
        for (int i = 0; i < CountNumbers; i++) {
            fw.write(new Random().nextInt(Integer.MAX_VALUE) + "\r\n");
        }
        fw.close();
        fs.close();

    }

    // 將大資料檔案切分到另外的十個小檔案中
    public static void sqlitFileDate(String filepath, String sqlitPath,
                                     int CountFile) throws IOException {
        FileWriter fs = null;
        BufferedWriter fw=null;
        FileReader fr = new FileReader(filepath + "\\12114.txt");
        BufferedReader br = new BufferedReader(fr); // 讀取獲取整行資料

        int i = 1;
        LinkedList WriterLists=new LinkedList();    //初始化檔案流物件集合
        LinkedList fwLists=new LinkedList();
        for (int j = 1; j <= CountFile; j++) {

            //宣告物件
            fs = new FileWriter(sqlitPath + "\\12" + j + ".txt",false);
            fw=new BufferedWriter(fs);

            //將物件裝入集合
            WriterLists.add(fs);
            fwLists.add(fw);
        }
        //判斷是檔案流中是否還有資料返回
        while (br.ready()) {
            int count=1;//初始化第一檔案流
            for (Iterator iterator = fwLists.iterator(); iterator.hasNext();) {
                BufferedWriter type = (BufferedWriter) iterator.next();
                if(i==count)//判斷輪到第幾個檔案流寫入資料了
                {
                    //寫入資料,跳出,進行下一個檔案流,下一個資料的寫入
                    type.write(br.readLine() + "\r\n");
                    break;
                }
                count++;
            }
            //判斷是否到了最後一個檔案流了
            if (i >= CountFile) {
                i = 1;
            } else
                i++;
        }
        br.close();
        fr.close();
        for (Iterator iterator = fwLists.iterator(); iterator.hasNext();) {
            BufferedWriter object = (BufferedWriter) iterator.next();
            object.close();
        }
        //遍歷關閉所有子檔案流
        for (Iterator iterator = WriterLists.iterator(); iterator.hasNext();) {
            FileWriter object = (FileWriter) iterator.next();
            object.close();
        }
    }

    // 把每個檔案的資料進行排序
    public static void singleFileDataSort(String path1,int CountFile) throws IOException {
        LinkedList nums = null;
        for (int i = 1; i <= CountFile; i++) {
            nums = new LinkedList();
            String path = path1 + "\\12" + i + ".txt";
            try {
                FileReader fr = new FileReader(path);
                BufferedReader br = new BufferedReader(fr);
                while (br.ready()) {
                    // 將讀取的單個資料加入到集合裡面
                    nums.add(Integer.parseInt(br.readLine()));
                }
                // 對集合進行排序
                Collections.sort(nums);

                // 將排序好的資料寫入原始檔
                numberSort(nums, path);
                br.close();
                fr.close();
            } catch (NumberFormatException e) {
                e.printStackTrace();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    // 對每個檔案資料進行排序,再寫入原始檔
    public static void numberSort(LinkedList list, String path) {
        try {
            FileWriter fs = new FileWriter(path);
            BufferedWriter fw=new BufferedWriter(fs);
            for (Iterator iterator = list.iterator(); iterator.hasNext();) {
                Object object = (Object) iterator.next();
                fw.write(object + "\r\n");
            }
            fw.close();
            fs.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 檔案資料最終整合(精度調整)
    public static void deathDataFile(String filepath, String sqlitFilePath1,
                   int countAccuracy, int CountFile) throws IOException {
        LinkedList nums = new LinkedList();//新增資料,進行排序
        Object temp = null; // 記錄每次排序剩下的最後一個數字
        boolean ispass = false;
        LinkedList ispasses = null;//記錄資料檔案的狀態資訊
        FileWriter fs = new FileWriter(filepath + "\\Sort.txt", false);//建立檔案流,以便整合的資料寫入
        BufferedWriter bw=new BufferedWriter(fs);
        FileReader fr = null; //宣告讀取檔案流
        BufferedReader br = null; //宣告BufferedReader
        LinkedList WriterLists = new LinkedList(); // 初始化檔案流物件集合
        LinkedList WriterListFile = new LinkedList();
        for (int j = 1; j <= CountFile; j++) {

            // 宣告物件,開啟所有子檔案流訪問所有子檔案的資料
            fr = new FileReader(sqlitFilePath1 + "\\12" + j + ".txt");

            //開啟所有BufferedReader,方便下次的整行的讀取
            br = new BufferedReader(fr);

            // 將所有 FileReader物件裝入集合
            WriterListFile.add(fr);

            // 將所有 BufferedReader物件裝入集合
            WriterLists.add(br);
        }

        for (;;) {

            // 將十個原始檔的是否有資料情況存入集合,以方便後面做判斷
            ispasses = new LinkedList();

            // 分別讀取十個原始檔的單個資料
            for (Iterator iterator = WriterLists.iterator(); iterator.hasNext();) {
                BufferedReader object = (BufferedReader) iterator.next();
                Object obj = null;
                while (object.ready()) {
                    //新增所有檔案流的每次的資料
                    nums.add(Integer.parseInt(object.readLine().toString()));
                    break;
                }
                if (object.ready() == false)
                    ispasses.add("true");           //將各檔案中的資料狀態存入集合中
            }

            // 決斷是否是第一次進來
            if (nums.size() % countAccuracy == 0 && ispass == false) {

                // 對集合進行排序
                Collections.sort(nums);

                // 接收最大的資料,其它的資料寫入總排序檔案
                temp = numberSortData(nums, filepath, false, countAccuracy, bw);

                //重新初始化集合
                nums = new LinkedList();

                // 新增上一組比較剩下的資料
                nums.add(temp);
                ispass = true;

                // 記錄原始檔的資料數量,以便下次的遍歷
                continue;
            }
            if (ispass) {
                if (nums.size() % countAccuracy == 1 && nums.size() > 1) {
                    // 對集合進行排序
                    Collections.sort(nums);

                    // 接收最大的資料,其它的資料寫入總排序檔案
                    temp = numberSortData(nums, filepath, true, countAccuracy,
                            bw);
                    nums = new LinkedList();
                    nums.add(temp);
                    continue;
                }

            }
            // 記錄下一組資料的位置

            // 判斷是不是十個檔案都沒有資料
            if (ispasses.size() == CountFile) {
                Collections.sort(nums);
                temp = numberSortData(nums, filepath, true, countAccuracy, bw);
                nums = new LinkedList();
                break;
            }
        }

        bw.close();
        //關閉寫入流
        fs.close();

        //關閉所有的BufferedReader
        for (Iterator iterator = WriterLists.iterator(); iterator.hasNext();) {
            BufferedReader object2 = (BufferedReader) iterator.next();
            object2.close();
        }

        //關閉所有的FileReader
        for (Iterator iterator = WriterListFile.iterator(); iterator.hasNext();) {
            FileReader object = (FileReader) iterator.next();
            object.close();
        }
    }

    // 對資料進行排序,寫入最終檔案中(精度調整)
    public static Object numberSortData(LinkedList list, String filePath,
               boolean ispass, int countAccuracy,BufferedWriter fs) {
        Object temp = 0;//記錄最後一個值
        int tempCount = 0;//記錄寫入的資料位置
        try {
            for (Iterator iterator = list.iterator(); iterator.hasNext();) {
                Object object = (Object) iterator.next();

                // 判斷是否是最後一個數
                if (tempCount == list.size() - 1) {
                    // 判斷集合裡面不足一百個數了
                    if (list.size() < countAccuracy + 1 && ispass) {
                        temp = null;
                    } else {
                        temp = object;
                        break;
                    }
                }

                // 寫入資料來源
                fs.write(object + "\r\n");

                // 記錄資料的下標
                tempCount++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return temp;
    }
}

相關文章