首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

Java 實現 PHP pack/unpack 函數相容類:十六進制字串與位元組陣列互轉

     編輯:PHP 綜合知識

PHP pack('H*', $hexStr) 與 unpack('H*', $binary) 常用於二進位協議、加密資料處理。Java 標準庫無直接對應方法,本文提供一個工具類 PackUtil,完整相容 PHP 行為,支援十六進制字串 ↔ 位元組陣列雙向轉換。

核心程式碼

package qghl.intp.util;

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

public class PackUtil {

    /**
     * 相容 PHP pack('H*', $str)
     * 將十六進制字串轉為 byte[]
     * 例:pack("48656c6c6f") → [0x48, 0x65, 0x6c, 0x6c, 0x6f] ("Hello")
     */
    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 c : str.toCharArray()) {
            byte n = (byte) c;
            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; // 在 4 和 0 之間切換
        }
        return output;
    }

    /**
     * 相容 PHP unpack('H*', $bin)
     * 將 byte[] 轉為十六進制字串(小寫,無前綴)
     */
    public static String unpack(byte[] bytes) {
        if (bytes == null || bytes.length == 0) return null;
        StringBuilder sb = new StringBuilder(bytes.length * 2);
        for (byte b : bytes) {
            int v = b & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) sb.append('0');
            sb.append(hv);
        }
        return sb.toString();
    }

    /** 從 InputStream 讀取指定長度並 unpack */
    public static String unpack(InputStream is, int len) throws IOException {
        byte[] bytes = new byte[len];
        int read = is.read(bytes);
        if (read != len) throw new IOException("Incomplete read");
        return unpack(bytes);
    }
}

行為驗證對照表

PHP 程式碼PHP 結果Java 呼叫Java 結果
pack('H*', '48656c6c6f')"Hello" (bytes)PackUtil.pack("48656c6c6f")[72, 101, 108, 108, 111]
unpack('H*', "Hello")['' => '48656c6c6f']PackUtil.unpack("Hello".getBytes())"48656c6c6f"
pack('H*', 'abc')[0xab, 0xc0] (奇數長度補 0)PackUtil.pack("abc")[0xab, 0xc0]

應用場景

  • PHP ↔ Java 微服務間透過十六進制字串傳遞二進位金鑰、簽名、加密資料
  • 資料庫儲存 VARBINARY 欄位,應用層以 Hex 字串序列化/反序列化
  • 舊系統遷移:PHP 端 pack() 產生的資料,Java 端用 PackUtil.unpack() 還原

注意事項

  1. 大小寫不敏感:pack() 接受大小寫混合的 Hex 字串,輸出 unpack() 固定小寫。
  2. 非法字元忽略:PHP pack('H*') 遇非 Hex 字元會跳過,本實作行為一致。
  3. 奇數長度補零:PHP 將 "abc" 視為 "ab" + "c0",本實作同樣處理。
  4. 效能優化:大量資料建議改用 DatatypeConverter.parseHexBinary() (JDK 內建) 或 Hex.decodeHex() (Apache Commons Codec),但需確認行為完全一致。

總結

PackUtil 以約 50 行程式碼完整複現 PHP pack/unpack('H*') 語意,解決跨語言二進位資料互通難題。專案若已引入 Commons Codec,建議改用 Hex 類別並撰寫單元測試驗證相容性,減少維護成本。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved