java使用ByteBuffer进行多文件合并和拆分

1.背景

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

2.代码工程

实验目的

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

合并代码

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

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

这个表达式的作用是将 publicCertsContent 数组的长度转换为二进制的 4 字节表示形式,并写入输出流(outputStream)中。这样在以后读取合并文件时,代码可以知道该读取多少字节属于 publicCertsContent。 有小伙伴这里可能有疑问,4字节够存多大数字呢? 4 个字节(即 32 位)在计算机中用于存储整数,能表示的整数范围如下:

  • 有符号整数(int 类型)
    • 范围是:-2,147,483,648 到 2,147,483,647
    • 其中 1 位用于符号(正负),31 位用于数值。
  • 无符号整数unsigned int,Java 中没有直接支持,但可以通过转换处理):
    • 范围是:0 到 4,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 outputStreamByteArrayOutputStream outputStream = new ByteArrayOutputStream();// write keystore length(4 byte)outputStream.write(ByteBuffer.allocate(4).putInt(privateKeysContent.length).array());// write keystore contentoutputStream.write(privateKeysContent);// witer license content(4 byte int )outputStream.write(ByteBuffer.allocate(4).putInt(publicCertsContent.length).array());// write license contentoutputStream.write(publicCertsContent);// write merge content to fileFileUtils.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 contentbyte[] mergedContent = FileUtils.readBinaryFile(mergedFile);// use ByteBuffer parseByteBuffer buffer = ByteBuffer.wrap(mergedContent);// read privateKeys content lengthint privateKeysLength = buffer.getInt();// read privateKeys contentbyte[] privateKeysContent = new byte[privateKeysLength];buffer.get(privateKeysContent);// read publicCerts content lengthint publicCertsLength = buffer.getInt();// read publicCerts contentbyte[] publicCertsContent = new byte[publicCertsLength];buffer.get(publicCertsContent);// write privateKeys and publicCerts content to fileFileUtils.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 markerbeginIndex += beginMarker.length;// Adjust endIndex to exclude the end markerint adjustedEndIndex = endIndex;// Extract contentreturn 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 linesList<byte[]> lines = splitIntoLines(content);// Filter out empty lineslines = lines.stream().filter(line -> line.length > 0).collect(Collectors.toList());// Reassemble contentreturn 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 breaklines.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);}}
}

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

代码仓库

  • https://github.com/Harries/Java-demo(file)

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

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

file

4.引用

  •  java使用ByteBuffer记录文件大小并进行多文件合并和拆分 | Harries Blog™

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/146177.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

threejs性能优化之gltf文件压缩threejs性能优化之glb文件压缩

在使用Three.js进行3D图形开发时&#xff0c;GLTF&#xff08;GL Transmission Format&#xff09;文件因其高效性和灵活性而广受欢迎。然而&#xff0c;随着模型复杂度的增加&#xff0c;GLTF文件的大小也会显著增加&#xff0c;这可能会对加载时间和渲染性能产生负面影响。为…

Redis数据结构之哈希表

这里的哈希表说的是value的类型是哈希表 一.相关命令 1.hset key field value 一次可以设置多个 返回值是设置成功的个数 注意&#xff0c;哈希表中的键值对&#xff0c;键是唯一的而值可以重复 所以有下面的结果&#xff1a; key中原来已经有了f1&#xff0c;所以再使用hse…

linux 操作系统下dhcrelay命令介绍和案例应用

linux 操作系统下dhcrelay命令介绍和案例应用 dhcrelay是一个用于DHCP&#xff08;动态主机配置协议&#xff09;中继的命令&#xff0c;主要功能是在没有本地DHCP服务器的子网中转发DHCP请求。这使得不同子网的DHCP客户端能够与位于其他子网中的DHCP服务器进行通信。 dhcrela…

基于微信小程序的购物系统+php(lw+演示+源码+运行)

基于微信小程序的购物系统 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了基于微信小程序的购物系统的开发全过程。通过分析基于微信小程序的购物系统管理的不足&#xff0c;创建了一个计算机管理基于微信小…

如何使用 Python 连接 MySQL 数据库?什么是 ORM(对象关系映射),如何使用

数据库是现代软件开发中的核心部分&#xff0c;而 Python 作为一种流行的编程语言&#xff0c;广泛应用于数据处理和分析工作。通常我们需要通过 Python 连接数据库并执行一些常见的操作&#xff0c;如插入、查询、更新和删除数据。在实际开发中&#xff0c;MySQL 是非常常用的…

LeetCode[中等] 155. 最小栈

设计一个支持 push &#xff0c;pop &#xff0c;top 操作&#xff0c;并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。void push(int val) 将元素val推入堆栈。void pop() 删除堆栈顶部的元素。int top() 获取堆栈顶部的元素。int get…

线程知识点补充

我们之前&#xff1a; 主线程下来&#xff0c;调用了一个方法run方法&#xff0c;方法执行完后再继续往下走主线程。 咱们期望&#xff1a; 两个同时执行&#xff0c;交替执行。 一些核心概念说明&#xff1a; 一个程序写好是静态的&#xff0c;给他运行起来就是一个进程了…

java计算机毕设课设—土地档案管理系统(附源码、文章、相关截图、部署视频)

这是什么系统&#xff1f; 资源获取方式在最下方 java计算机毕设课设—土地档案管理系统(附源码、文章、相关截图、部署视频) 土地档案管理系统是一种将传统纸质档案进行数字化管理的软件。通过该系统&#xff0c;用户能够高效地进行土地档案的存储、查阅、修改和删除等操作…

unity3d入门教程八-飞机大战

unity3d入门教程八-飞机大战 19.2竖屏设置19.3主控脚本19.4制作子弹19.5制作飞机19.6制作怪物19.7击中目标19.8随机生成怪物19.9预制体怪物随机更换头像19.10怪物相关优化19.11游戏背景19.12游戏最终优化一、 HP显示二、怪物预制体三、分值显示四、背景音乐 19.2竖屏设置 切换到…

鸿蒙媒体开发系列08——AudioCapturer录制音频

如果你也对鸿蒙开发感兴趣&#xff0c;加入“Harmony自习室”吧&#xff01;扫描下方名片&#xff0c;关注公众号&#xff0c;公众号更新更快&#xff0c;同时也有更多学习资料和技术讨论群。 1、概述 我们在鸿蒙媒体开发系列07——AVRecorder音频录制中我们了解到&#xff0c…

【后端开发】JavaEE初阶—线程的理解和编程实现

前言&#xff1a; &#x1f31f;&#x1f31f;本期讲解多线程的知识哟~~~&#xff0c;希望能帮到屏幕前的你。 &#x1f308;上期博客在这里&#xff1a;【后端开发】JavaEE初阶——计算机是如何工作的&#xff1f;&#xff1f;&#xff1f;-CSDN博客 &#x1f308;感兴趣的小伙…

Linux介绍;Linux安装;Linux常见错误

一&#xff0c;Linux简介 1.1操作系统 指人和计算机硬件沟通交流的平台。 1.2常见的操作系统 1.21 PC windows MacOS Linux 1.22 移动端 Android IOS 鸿蒙 塞班 1.3什么是Linux Linux&#xff0c;一般指GNU/Linux&#xff08;单独的Linux内核并不可直接使用&…

【漏洞复现】泛微OA E-Office jx2_config.ini 敏感信息泄漏漏洞

免责声明&#xff1a; 本文内容旨在提供有关特定漏洞或安全漏洞的信息&#xff0c;以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步&#xff0c;并非出于任何恶意目的。阅读者应该明白&#xff0c;在利用本文提到的漏洞信息或进行相关测…

buucft hashcat

使用文本编辑器打开时乱码 使用010editor打开发现时xml文档 拷贝到kali&#xff0c;使用binwalk查看&#xff0c;发现时xml文档&#xff0c;改后缀名为ppt。打开发现有密码 Accent OFFICE Password Recovery 64位-Office密码恢复软件 v20.09 免费版 - 下载吧 试试这个Accent O…

飞腾计算模块RapidIO性能测试

1、背景介绍 飞腾计算模块采用FT2000 64核处理器&#xff0c;搭配Tsi721 PCIE转RapidIO芯片&#xff0c;实现飞腾平台下的SRIO数据通信。操作系统采用麒麟信安&#xff0c;内核版本4.19.90. 2、驱动加载 驱动加载部分类似之前写过的X86平台下的RapidIO驱动加载&#xff0c;具…

Ngnix 在windows上的简单使用

安装 下载链接: nginx: download 选择页面中 Stable version 下的windows版本直接下载解压到本地。 运行nginx: 解压到本地后,结构如图: cmd 进入到上图的根目录,运行 start nginx ,即可开启。 打开 http://localhost 进行查看,如果正常打开nginx的测试页面,则说…

借10万块,年化利息明明是3.8%,为啥就变成了2.07%?

今天咱们来聊一聊贷款的奥秘&#xff0c;特别是那个令人爱恨交织的年利率。听起来直观得很&#xff0c;3.8%就像是每年给银行支付贷款总额的3.8%作为利息&#xff0c;但实际上&#xff0c;这里面的学问挺深的。有时候&#xff0c;名义上的3.8%年化&#xff0c;最终一算&#xf…

电子元器件之MOS管,附上几个常用MOS管电路和仿真。

MOS管是一种常用的电子元器件。 1.MOS管的类别 MOSFET简称MOS&#xff0c;是一种绝缘栅型场效应管。按照类别可以分为增强型mos管和耗尽型mos管。 导电沟道的形成方式‌ 增强型MOS管&#xff1a;在没有外加电压时&#xff0c;源极和漏极之间没有导电沟道存在。只有当栅极电…

打开Anaconda Navigator没反应,卡在Initializing...的解决方案

一、问题描述 打开Anaconda Navigator时&#xff0c;一直卡在Initializing...没反应&#xff0c;如下图所示&#xff1a; 二、解决方案 进入Anaconda安装目录下找到并打开文件夹attribution&#xff08;笔者Anaconda安装目录在D盘下&#xff0c;读者可自行查找自己安装目录中…

基于stm32物联网身体健康检测系统

在当今社会&#xff0c;由于经济的发展带来了人们生活水平不断提高&#xff0c;但是人们的健康问题却越来越突出了&#xff0c;各种各样的亚健康随处可在&#xff0c;失眠、抑郁、焦虑症&#xff0c;高血压、高血糖等等侵袭着人们的健康&#xff0c;人们对健康的关注达到了一个…