Java实现PHP pack与unpack功能的16进制转换工具

码头散步
码头散步
发布时间:2026-10-13 | 5人浏览过
原创

针对Java开发中需要处理与PHP系统交互时常见的16进制数据转换需求,本文提供了一段完整的工具代码。该实现模拟了PHP中的pack(打包/编码)和unpack(解包/解码)机制,支持将16进制文本解析为字节数组,以及将字节数组还原为标准的16进制字符序列。

问题背景与适用场景

在分布式系统或微服务架构中,不同技术栈的服务往往需要进行二进制或十六进制数据的交换。PHP中的pack()和unpack()函数常用于处理此类二进制结构数据。若Java服务需要兼容旧有的PHP接口或处理由PHP生成的16进制数据包,直接使用标准库可能不够直观。以下工具类提供了简易的实现方案。

准备条件

  1. 依赖环境:Java Standard Edition (JDK 8及以上版本)。
  2. 核心需求:需要一个能够处理字节流与十六进制字符串相互转换的组件。
  3. 代码位置:建议新建qghl.intp.util包(可根据实际项目包名调整)并放置PackUtil.java文件。

详细操作顺序

第1步:创建工具类框架

目的:建立基础的工具类容器,导入必要的IO流支持。

  • 入口:IDE新建Java Class。PackUtil。
  • 动作:添加java.io.IOException和java.io.InputStream的import语句。

第2步:实现16进制字符串到字节的转换(Pack)

目的:对应PHP的pack逻辑,将包含0-9、A-F/a-f的字符串解析为对应的字节数据。

  • 关键参数:输入为String类型,输出为byte[]。
  • 注意:该实现采用位运算逻辑(移位与掩码)逐个字符处理。对于非十六进制字符会自动跳过,适合清洗后的输入数据。
package qghl.intp.util;

import java.io.IOException;
import java.io.InputStream;

public class PackUtil {

    /**
     * 打包字符串 - 类似php中pack在java中的实现
     *
     * @param str 16进制格式的字符串
     * @return 转换后的字节数组
     */
    public static byte[] pack(String str) {
        int nibbleshift = 4;
        int position = 0;
        // 计算输出长度:每两个字符合成一个字节
        int len = str.length() / 2 + str.length() % 2;
        byte[] output = new byte[len];
        
        for (char v : str.toCharArray()) {
            byte n = (byte) v;
            // 判断字符类型并转换为数值 0-15
            if (n >= '0' && n <= '9') {
                n -= '0';
            } else if (n >= 'A' && n <= 'F') {
                n -= ('A' - 10);
            } else if (n >= 'a' && n <= 'f') {
                n -= ('a' - 10);
            } else {
                continue; // 忽略非十六进制字符
            }
            
            // 位操作合并字节:奇数位高四位,偶数位低四位
            output[position] |= (n << nibbleshift);

            if (nibbleshift == 0) {
                position++;
            }
            nibbleshift = (nibbleshift + 4) & 7;
        }

        return output;
    }

    // ... (后续方法见下文)
}

第3步:实现字节流与数组的解压(Unpack)

目的:对应PHP的unpack逻辑,将传入的输入流或字节数组转换为16进制大写/小写混合的标准字符串表示。

  • 重载方法:提供接受InputStream的方法用于流式读取,以及直接接受byte[]的方法用于内存操作。
  • 完成状态:返回的字符串长度应为原字节数组长度的两倍,不足两位的十进制数前补零。
    /**
     * 从输入流中解压16进制字符串
     *
     * @param is   输入流
     * @param len  读取长度
     * @return     16进制字符串
     * @throws IOException IO异常
     */
    public static String unpack(InputStream is, int len) throws IOException {
        byte[] bytes = new byte[len];
        is.read(bytes);
        return unpack(bytes);
    }

    /**
     * 字节数组解压为16进制字符串
     *
     * @param bytes 源字节数组
     * @return      16进制字符串
     */
    public static String unpack(byte[] bytes) {
        StringBuilder stringBuilder = new StringBuilder("");
        if (bytes == null || bytes.length <= 0) {
            return null;
        }
        
        for (int i = 0; i < bytes.length; i++) {
            int v = bytes[i] & 0xFF; // 转为无符号整数,防止负号干扰hex转换
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0); // 补零
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }
}

使用示例

假设我们需要将一个16进制字符串"48656c6c6f"(即"Hello"的ASCII码)进行编解码:

public class MainTest {
    public static void main(String[] args) throws Exception {
        String hexStr = "48656c6c6f";
        
        // 1. 执行 pack: 字符串 -> 字节
        byte[] data = PackUtil.pack(hexStr);
        System.out.println("Bytes length: " + data.length);
        
        // 2. 执行 unpack: 字节 -> 字符串
        String result = PackUtil.unpack(data);
        System.out.println("Result: " + result); // 输出: 48656c6c6f
    }
}

注意事项与风险排查

  • 编码规范:上述pack方法在处理奇数个字符时会截断最后一个半字节,这在常规16进制配对场景中较少见,但需留意。
  • 负值处理:在unpack中使用了& 0xFF来确保Java的byte(有符号)正确转换为十六进制字符串,这是正确的做法,避免了因负数导致的-7f等意外输出。
  • 性能提示:对于大量数据,建议使用BufferedInputStream包裹输入流以提高I/O效率。

简要总结

以上关于Java模拟PHP的pack和unpack功能的详细内容,更多关于Java PHP交叉开发及16进制处理的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表