zoukankan      html  css  js  c++  java
  • 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) + "毫秒");
        }
    }
    
    
  • 相关阅读:
    CODING x 百果园 _ 水果零售龙头迈出 DevOps 体系建设第一步
    Nocalhost 亮相 CD Foundation 国内首届 Meetup,Keith Chan 将出席致辞
    做云原生时代标准化工具,实现高效云上研发工作流
    打造数字化软件工厂 —— 一站式 DevOps 平台全景解读
    WePack —— 助力企业渐进式 DevOps 转型
    CODING Compass —— 打造行云流水般的软件工厂
    Nocalhost —— 让云原生开发回归原始而又简单
    CODING 代码资产安全系列之 —— 构建全链路安全能力,守护代码资产安全
    Nocalhost:云原生开发新体验
    使用 Nocalhost 开发 Kubernetes 中的 APISIX Ingress Controller
  • 原文地址:https://www.cnblogs.com/zyoung/p/7803347.html
Copyright © 2011-2022 走看看