当前位置: 代码网 > it编程>编程语言>Java > Java使用ByteBuffer进行多文件合并和拆分的代码实现

Java使用ByteBuffer进行多文件合并和拆分的代码实现

2024年09月22日 Java 我要评论
1.背景因为验证证书的需要,需要把证书文件和公钥给到客户,考虑到多个文件交互的不便性,所以决定将2个文件合并成一个文件交互给客户。刚开始采用字符串拼接2个文件内容,但是由于是加密文件,采用字符串形式合

1.背景

因为验证证书的需要,需要把证书文件和公钥给到客户,考虑到多个文件交互的不便性,所以决定将2个文件合并成一个文件交互给客户。刚开始采用字符串拼接2个文件内容,但是由于是加密文件,采用字符串形式合并后,拆分后文件不可用,最后采用基于二进制流拆分和合并文件,效果不错!

2.代码工程

实验目的

对文件进行二进制流合并和拆分

合并代码

bytebuffer.allocate(4).putint(publiccertscontent.length).array() 的作用是将 publiccertscontent(公钥证书内容)的长度转换为 4 个字节的整数,并写入到字节缓冲区中。具体作用如下:

  • bytebuffer.allocate(4): 创建一个大小为 4 字节的 bytebuffer,因为 java 中的整数(int)是 4 个字节。
  • putint(publiccertscontent.length): 将 publiccertscontent 的字节数组长度(即证书文件的字节长度)存入 bytebuffer。这样就把证书内容的长度存储为一个 4 字节的整数。
  • array(): 将 bytebuffer 转换为字节数组。这个数组包含了公钥证书内容长度的 4 字节表示形式。

这个表达式的作用是将 publiccertscontent 数组的长度转换为二进制的 4 字节表示形式,并写入输出流(outputstream)中。这样在以后读取合并文件时,代码可以知道该读取多少字节属于 publiccertscontent

有小伙伴这里可能有疑问,4字节够存多大数字呢?

4 个字节(即 32 位)在计算机中用于存储整数,能表示的整数范围如下:

  • 有符号整数(int 类型)
    • 范围是:-2,147,483,6482,147,483,647
    • 其中 1 位用于符号(正负),31 位用于数值。
  • 无符号整数unsigned int,java 中没有直接支持,但可以通过转换处理):
    • 范围是:04,294,967,295

通常 java 中的 int 类型是有符号的,因此 4 个字节可以存储的整数范围为 -2^31 到 2^31 - 1,即 -2,147,483,648 到 2,147,483,647。所以只要不超过这个限制都能存下来

package com.et;


import java.io.bytearrayoutputstream;
import java.io.ioexception;
import java.nio.bytebuffer;


public class filemerger {

    public static void main(string[] args) {
        string privatekeys = "d:/ideaprojects/java-demo/file/src/main/resources/privatekeys.keystore";
        string publiccerts = "d:/ideaprojects/java-demo/file/src/main/resources/publiccerts.keystore";
        merger(privatekeys,publiccerts);

    }
    public static string merger(string privatekeys, string publiccerts) {
        string directorypath = fileutils.extractdirectorypath(privatekeys);
        string mergedfile =directorypath+"merge.keystore";

        try {
            byte[] privatekeyscontent =   fileutils.readbinaryfile(privatekeys);
            byte[] publiccertscontent =   fileutils.readbinaryfile(publiccerts);


            // create outputstream
            bytearrayoutputstream outputstream = new bytearrayoutputstream();

            // write keystore length(4 byte)
            outputstream.write(bytebuffer.allocate(4).putint(privatekeyscontent.length).array());

            // write keystore content
            outputstream.write(privatekeyscontent);

            // witer license content(4 byte int )
            outputstream.write(bytebuffer.allocate(4).putint(publiccertscontent.length).array());

            // write license content
            outputstream.write(publiccertscontent);

            // write merge content to file
            fileutils.writebinaryfile(mergedfile, outputstream.tobytearray());
          
            system.out.println("merge success " + mergedfile);
        } catch (ioexception e) {
            e.printstacktrace();
        }
        return mergedfile;
    }



}

拆分代码

拆分逻辑就很简单了,先读取4字节,获取文件大小,然后依次获取文件内容就可以了 buffer.getint() 可以正确读取文件中的大小信息。具体来说,它会从 bytebuffer 中读取 4 个字节,并将这些字节解释为一个整数。 如果你按照之前的代码将文件内容合并时,将文件大小以 4 字节整数形式写入到文件中,那么你可以使用 buffer.getint() 来读取这个大小。例如,假设你在合并文件时使用了如下方式写入大小:

outputstream.write(bytebuffer.allocate(4).putint(content.length).array());

在读取合并文件时,你可以这样做:

bytebuffer buffer = bytebuffer.wrap(filecontent); // 假设 filecontent 是读取的字节数组
int size = buffer.getint(); // 读取前 4 个字节,获取文件大小

这里的 buffer.getint() 会正确读取到前 4 个字节,并将其转换为整数,这样你就得到了文件内容的大小。 请确保在读取文件时,字节顺序(字节序)与写入时一致,默认情况下是大端序(big endian)。如果你的应用需要小端序(little endian),你可以使用 buffer.order(byteorder.little_endian) 来设置字节序。

package com.et;


import java.io.bytearrayoutputstream;
import java.io.ioexception;
import java.nio.bytebuffer;
import java.util.arraylist;
import java.util.arrays;
import java.util.list;
import java.util.stream.collectors;


public class filesplitter {

    public static void main(string[] args) {
        string mergedfile = "d:/ideaprojects/java-demo/file/src/main/resources/merge.keystore";
        split(mergedfile);

    }
    private static void debugcontent(byte[] content, string filename) {
        system.out.printf("file: %s%n", filename);
        system.out.printf("length: %d%n", content.length);
        system.out.print("content: ");
        for (byte b : content) {
            system.out.printf("%02x ", b);
        }
        system.out.println();
    }
    static string[] split(string mergedfile) {
        string directorypath = fileutils.extractdirectorypath(mergedfile);
        string privatekeysfile = directorypath + ".privatekeys.keystore";
        string publiccertsfile = directorypath + ".publiccerts.keystore";
        string[] filepaths = new string[]{privatekeysfile, publiccertsfile};

        try {
            // read merge content
            byte[] mergedcontent = fileutils.readbinaryfile(mergedfile);

            // use bytebuffer parse
            bytebuffer buffer = bytebuffer.wrap(mergedcontent);

            // read privatekeys content length
            int privatekeyslength = buffer.getint();

            // read privatekeys content
            byte[] privatekeyscontent = new byte[privatekeyslength];
            buffer.get(privatekeyscontent);

            // read publiccerts content length
            int publiccertslength = buffer.getint();

            // read publiccerts content
            byte[] publiccertscontent = new byte[publiccertslength];
            buffer.get(publiccertscontent);

            // write privatekeys and publiccerts content to file
            fileutils.writebinaryfile(privatekeysfile, privatekeyscontent);
            fileutils.writebinaryfile(publiccertsfile, publiccertscontent);

            system.out.println("merge file split " + privatekeysfile + " and " + publiccertsfile);

        } catch (ioexception e) {
            e.printstacktrace();
        }

        return filepaths;
    }






    private static byte[] extractcontent(byte[] mergedcontent, byte[] beginmarker, byte[] endmarker) {
        int beginindex = indexof(mergedcontent, beginmarker);
        int endindex = indexof(mergedcontent, endmarker, beginindex);

        if (beginindex != -1 && endindex != -1) {
            // move past the start marker
            beginindex += beginmarker.length;

            // adjust endindex to exclude the end marker
            int adjustedendindex = endindex;

            // extract content
            return arrays.copyofrange(mergedcontent, beginindex, adjustedendindex);
        } else {
            return new byte[0]; // return empty array if markers are not found
        }
    }


    private static byte[] removeemptylines(byte[] content) {
        // convert byte array to list of lines
        list<byte[]> lines = splitintolines(content);

        // filter out empty lines
        lines = lines.stream()
                .filter(line -> line.length > 0)
                .collect(collectors.tolist());

        // reassemble content
        return mergelines(lines);
    }

    private static list<byte[]> splitintolines(byte[] content) {
        list<byte[]> lines = new arraylist<>();
        int start = 0;

        for (int i = 0; i < content.length; i++) {
            if (content[i] == '\n') { // line break
                lines.add(arrays.copyofrange(content, start, i));
                start = i + 1;
            }
        }

        if (start < content.length) {
            lines.add(arrays.copyofrange(content, start, content.length));
        }

        return lines;
    }

    private static byte[] mergelines(list<byte[]> lines) {
        bytearrayoutputstream outputstream = new bytearrayoutputstream();
        for (byte[] line : lines) {
            try {
                outputstream.write(line);
                outputstream.write('\n'); // re-add line break
            } catch (ioexception e) {
                e.printstacktrace();
            }
        }
        return outputstream.tobytearray();
    }

    private static int indexof(byte[] array, byte[] target) {
        return indexof(array, target, 0);
    }

    private static int indexof(byte[] array, byte[] target, int start) {
        for (int i = start; i <= array.length - target.length; i++) {
            if (arrays.equals(arrays.copyofrange(array, i, i + target.length), target)) {
                return i;
            }
        }
        return -1; // return -1 if target not found
    }






}

工具类

package com.et;

import java.io.file;
import java.io.fileinputstream;
import java.io.fileoutputstream;
import java.io.ioexception;

public class fileutils {

    static byte[] readbinaryfile(string filepath) throws ioexception {
        file file = new file(filepath);
        try (fileinputstream fis = new fileinputstream(file)) {
            byte[] filebytes = new byte[(int) file.length()];
            fis.read(filebytes);
            return filebytes;
        }
    }
    public static string extractdirectorypath(string filepath) {
        file file = new file(filepath);
        return file.getparent()+file.separator; // 获取文件所在的目录
    }
     static void writebinaryfile(string filepath, byte[] content) throws ioexception {
        try (fileoutputstream fos = new fileoutputstream(filepath)) {
            fos.write(content);
        }
    }
}

以上只是一些关键代码,所有代码请参见下面代码仓库

代码仓库

3.测试

测试类

package com.et;

public class main {
    public static void main(string[] args) {
        system.out.println("hello world!");
        string privatekeys = "d:/ideaprojects/java-demo/file/src/main/resources/privatekeys.keystore";
        string publiccerts = "d:/ideaprojects/java-demo/file/src/main/resources/publiccerts.keystore";
        filemerger.merger(privatekeys,publiccerts);
        string mergedfile = "d:/ideaprojects/java-demo/file/src/main/resources/merge.keystore";
        filesplitter.split(mergedfile);
    }
}

运行main方法,日志显示如下

merge success d:\ideaprojects\java-demo\file\src\main\resources\merge.keystore
merge file split d:\ideaprojects\java-demo\file\src\main\resources\.privatekeys.keystore and d:\ideaprojects\java-demo\file\src\main\resources\.publiccerts.keystore

拆分后文件于原文件大小一模一样

以上就是java使用bytebuffer进行多文件合并和拆分的代码实现的详细内容,更多关于java bytebuffer文件合并和拆分的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com