• bson文件的切分


    描述

    最近遇到问题需要将较大的bson文件(MongoDB导出的二进制json文件)按文档(记录)进行切分,网上这方面的资料实在太少,弄了一天多终于达到了基本要求(还不知道有没有BUG)

    代码

    package splitbson;
    
    import java.io.*;
    import java.util.Scanner;
    
    /**
     * 每条文档的前四个字节表示该文档的字节数,因此只需要读取4个字节数,计算该文档大小。然后用字节流读取即可。
     */
    public class SplitBsonUtils {
        // 输入流
        private static BufferedInputStream bis;
        // 输出结果文件的命名编号
        private static int fileNameCount = 1;
        // 带缓冲区的输出流
        private static BufferedOutputStream bos;
        // 记录当前文件已写文档(记录)数
        private static int documentCount = 0;
    
        /**
         * 切分bson文件
         *
         * @param sourceFilePath  源bson文件
         * @param fileDocumentNum 每个文件的文档数
         * @param targetFilePath  目标文件目录
         */
        public static void splitBson(String sourceFilePath, int fileDocumentNum, String targetFilePath) {
            if (fileDocumentNum < 0) fileDocumentNum = 100;
            try {
                // 构建输入流
                bis = new BufferedInputStream(new FileInputStream(sourceFilePath));
                File dir = new File(targetFilePath);
                if (!dir.exists()) {
                    dir.mkdir();
                }
                // 构建可缓冲的输出流
                bos = new BufferedOutputStream(new FileOutputStream(targetFilePath + "/file" + fileNameCount++ + ".bson", true));
                // 获取下一条记录的字节数
                int documentSize = getSize(sourceFilePath);
                // 减4是因为getSize方法已经读写了四个字节
                byte[] arr = new byte[documentSize - 4];
                // 开始读源bson文件
                while (bis.read(arr) != -1) {
                    // 写入到新的文件
                    bos.write(arr);
                    documentCount++;
                    // 判断当前文件记录数是否达到自定义文档数
                    if (documentCount == fileDocumentNum) {
                        // 创建新的输出流
                        bos = new BufferedOutputStream(new FileOutputStream(targetFilePath + "/file" + fileNameCount++ + ".bson", true));
                        documentCount = 0;
                    }
                    documentSize = getSize(sourceFilePath);
                    // 表示已经到了文件结尾
                    if (documentSize == -1) break;
                    arr = new byte[documentSize - 4];
                }
                bos.flush();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    bis.close();
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * 获取源bson文件正被读取文档的字节数
         *
         * @param filePath
         * @return
         */
        public static int getSize(String filePath) {
            byte[] arr = new byte[4];
            int size = 0;
            try {
                bis.read(arr);
                size = byte2DecStr(arr);
                if (size - 4 < 0) return -1;
                bos.write(arr);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return size;
        }
    
        /**
         * byte数组转换成十进制字符串
         *
         * @param b
         * @return
         */
        public static int byte2DecStr(byte[] b) {
            String stmp = "";
            StringBuilder sb = new StringBuilder("");
            for (int n = b.length - 1; n >= 0; n--) {
                stmp = Integer.toHexString(b[n] & 0xFF);
                sb.append((stmp.length() == 1) ? "0" + stmp : stmp);
            }
            return Integer.parseInt(sb.toString(), 16);
        }
    
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            System.out.println("请传入三个参数进行bson文件的切分:");
            System.out.println("1. 原bson文件绝对路径(无需引号),如:E:/ld_FamilySearch_detail.bson");
            String sourceFilePath = scanner.nextLine();
            System.out.println("2. 切分后每个文件所要存储的文档(记录)条数,如:100");
            int fileDocumentNum = scanner.nextInt();
            scanner.nextLine();
            System.out.println("3. 切分后文件存储的目录(无需引号),如:E:/result");
            String targetFilePath = scanner.nextLine();
            System.out.println(sourceFilePath + fileDocumentNum + targetFilePath);
            System.out.println("正在进行切分...");
            long start = System.currentTimeMillis();
            splitBson(sourceFilePath, fileDocumentNum, targetFilePath);
            long end = System.currentTimeMillis();
            System.out.println("切分完成!共耗时:" + (end - start) + "毫秒");
        }
    }
    
    
  • 相关阅读:
    KMeans算法分析以及实现
    决策树(ID3,C4.5,CART)原理以及实现
    [推荐系统读书笔记]利用用户标签数据
    [推荐系统读书笔记]推荐系统冷启动问题
    [推荐系统]利用用户行为数据
    [推荐系统读书笔记]好的推荐系统
    Docker Hub国内镜像加速
    ubuntu下cannot connect to X server :1
    vscode编写C++设置左花括号不换行
    SLAM十四讲中Sophus库安装
  • 原文地址:https://www.cnblogs.com/zyoung/p/7803347.html
Copyright © 2020-2023  润新知