JAVA实现Python中struct.pack()和struct.unpack()方法,并增加比特类型支持


package jelly.command.coder.util;

import jelly.command.coder.exception.CmdCodecException;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
import com.google.common.primitives.Shorts;
import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin;
import org.apache.commons.lang3.ArrayUtils;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

public class CoderUtil {

    public static void main(String[] args) throws Exception {
        String pattern = "h2,h4,s,h4,i";
        System.out.println(pattern);
        String value = "621E,0000FEB1,29,FFFFFFFF,21";
        System.out.println(value);
        String encode = HexBin.encode(encode(pattern, value, false));
        System.out.println(encode);
        System.out.println(String.join(",",decode(pattern,HexBin.decode(encode),false)));

    }

    public static List<String> getSrcCode(byte[] bytes, String pattern) throws CmdCodecException {
        pattern = pattern.replace("i", "i4")
                .replace("s", "s2")
                .replace("f", "f4")
                .replace("l", "l8");
        boolean hasBit = pattern.contains("b");
        byte[] bits = BitUtils.bytesToBits(bytes);
        ByteBuffer bytesBuf = ByteBuffer.wrap(bytes);
        bytesBuf.position(0);
        ByteBuffer bitsBuf = ByteBuffer.wrap(bits);
        bitsBuf.position(0);
        List<String> srcCodeList = new ArrayList<>();
        String[] pa = pattern.split(",");
        for (String s : pa) {
            String type = s.substring(0, 1);
            int len = Integer.parseInt(s.substring(1));
            byte[] bytesTemp;
            len = hasBit && !type.equals("b") ? len * 8 : len;
            bytesTemp = new byte[len];
            if (hasBit) {
                bitsBuf.get(bytesTemp, 0, len);
            } else {
                bytesBuf.get(bytesTemp, 0, len);
            }
            switch (type) {
                case "i":
                case "s":
                case "l":
                case "f":
                case "h":
                    srcCodeList.add(HexBin.encode(hasBit ? BitUtils.bitsToBytes(bytesTemp) : bytesTemp));
                    break;
                case "b":
                    StringBuilder sb = new StringBuilder();
                    for (byte b : bytesTemp) sb.append(b);
                    srcCodeList.add(sb.toString());
                    break;
                default:
                    throw new CmdCodecException("not support this type : " + type);
            }
        }
        return srcCodeList;
    }


    /**
     * @param pattern 字节数组的属性格式
     *                例如:i,s,l,h4,b8,其中h和b后面需要指定字节长度
     *                i:表示4个字节的int
     *                s:表示2个字节的short,
     *                l:表示8个字节的long,
     *                h4:表示4个字节的16进制,
     *                b8:表示8个比特
     * @param value   各属性的标示值,用“,”分割。例如:"2,3,4,A1B1C1D1,00001111"
     * @return 组合后的字节数组
     * @throws CmdCodecException 不支持类型
     */
    public static byte[] encode(String pattern, String value, boolean isLittleEndian) throws CmdCodecException {
        pattern = pattern.replace("i", "i4")
                .replace("s", "s2")
                .replace("f", "f4")
                .replace("l", "l8");
        String[] parArr = pattern.split(",");
        String[] vaArr = value.split(",");
        boolean hasBit = pattern.contains("b");
        List<byte[]> bytesList = new ArrayList<>();
        for (int i = 0; i < parArr.length; i++) {
            String type = parArr[i].substring(0, 1);
            String num = parArr[i].substring(1);
            int len = Integer.parseInt(num);
            String strValue = vaArr[i];
            byte[] bytes;
            switch (type) {
                case "i":
                    bytes = Ints.toByteArray(Integer.parseInt(strValue));
                    if (isLittleEndian) ArrayUtils.reverse(bytes);
                    bytesList.add(hasBit ? BitUtils.bytesToBits(bytes) : bytes);
                    break;
                case "s":
                    bytes = Shorts.toByteArray(Short.parseShort(strValue));
                    if (isLittleEndian) ArrayUtils.reverse(bytes);
                    bytesList.add(hasBit ? BitUtils.bytesToBits(bytes) : bytes);
                    break;
                case "f":
                    float[] floats = {Float.parseFloat(strValue)};
                    bytes = ByteUtils.floatArrToByteArr(floats);
                    if (isLittleEndian) ArrayUtils.reverse(bytes);
                    bytesList.add(hasBit ? BitUtils.bytesToBits(bytes) : bytes);
                    break;
                case "l":
                    bytes = Longs.toByteArray(Long.parseLong(strValue));
                    if (isLittleEndian) ArrayUtils.reverse(bytes);
                    bytesList.add(hasBit ? BitUtils.bytesToBits(bytes) : bytes);
                    break;
                case "h":
                    bytes = HexBin.decode(strValue);
                    byte[] bytes1 = new byte[len];
                    System.arraycopy(bytes, 0, bytes1, len - bytes.length, bytes.length);
                    if (isLittleEndian) ArrayUtils.reverse(bytes1);
                    bytesList.add(hasBit ? BitUtils.bytesToBits(bytes1) : bytes1);
                    break;
                case "b":
                    bytes = new byte[strValue.length()];
                    for (int k = 0; k < strValue.length(); k++) {
                        bytes[k] = Byte.parseByte(String.valueOf(strValue.charAt(k)));
                    }
                    bytes1 = new byte[len];
                    System.arraycopy(bytes, 0, bytes1, len - bytes.length, bytes.length);
                    bytesList.add(bytes);
                    break;
                default:
                    throw new CmdCodecException("not support this type : " + type);
            }
        }
        int len = 0;
        for (byte[] bytes : bytesList) {
            len += bytes.length;
        }
        ByteBuffer buffer = ByteBuffer.allocate(len);
        for (byte[] bytes : bytesList) {
            buffer.put(bytes);
        }
        return hasBit ? BitUtils.bitsToBytes(buffer.array()) : buffer.array();
    }

    public static String[] decode(String pattern, byte[] bytes, boolean isLittleEndian) throws CmdCodecException {
        pattern = pattern.replace("i", "i4")
                .replace("s", "s2")
                .replace("f", "f4")
                .replace("l", "l8");
        boolean hasBit = pattern.contains("b");
        byte[] bits = BitUtils.bytesToBits(bytes);
        ByteBuffer bytesBuf = ByteBuffer.wrap(bytes);
        bytesBuf.position(0);
        ByteBuffer bitsBuf = ByteBuffer.wrap(bits);
        bitsBuf.position(0);
        String[] parArr = pattern.split(",");
        String[] resultArr = new String[parArr.length];
        for (int i = 0; i < parArr.length; i++) {
            String s = parArr[i];
            String type = s.substring(0, 1);
            int len = Integer.parseInt(s.substring(1));
            byte[] bytesTemp;
            len = hasBit && !type.equals("b") ? len * 8 : len;
            bytesTemp = new byte[len];
            if (hasBit) {
                bitsBuf.get(bytesTemp, 0, len);
            } else {
                bytesBuf.get(bytesTemp, 0, len);
            }
            byte[] tmp = hasBit ? BitUtils.bitsToBytes(bytesTemp) : bytesTemp;
            if (isLittleEndian){
                ArrayUtils.reverse(tmp);
            }
            switch (type) {
                case "i":
                    resultArr[i] = String.valueOf(Ints.fromByteArray(tmp));
                    break;
                case "s":
                    resultArr[i] = String.valueOf(Shorts.fromByteArray(tmp));
                    break;
                case "l":
                    resultArr[i] = String.valueOf(Longs.fromByteArray(tmp));
                    break;
                case "f":
                    resultArr[i] = String.valueOf(ByteUtils.byteArrToFloatArr(tmp)[0]);
                    break;
                case "h":
                    resultArr[i] = HexBin.encode(tmp);
                    break;
                case "b":
                    StringBuilder sb = new StringBuilder();
                    for (byte b : bytesTemp) sb.append(b);
                    resultArr[i] = sb.toString();
                    break;
                default:
                    throw new CmdCodecException("not support this type : " + type);
            }
        }
        return resultArr;
    }
}

相关工具类

package jelly.command.coder.util;

import com.google.common.primitives.Ints;
import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin;

import java.util.Arrays;

/**
 * @Date 2020/12/26 17:08
 * @Version 1.0
 * @Description
 */
public class BitUtils {

    public static void main(String[] args) {
        System.out.println(Arrays.toString(hexStrToBits("0013")));
        System.out.println(bitStrToHex("00000010011"));
    }

    public static byte bitStrToByte(String bitStr) {
        int re, len;
        if (bitStr == null) {
            return 0;
        }
        len = bitStr.length();
        if (len != 4 && len != 8) {
            return 0;
        }
        if (len == 8) {//8 bit 处理
            if (bitStr.charAt(0) == '0') {
                re = Integer.parseInt(bitStr, 2);
            } else {//负数
                re = Integer.parseInt(bitStr, 2) - 256;
            }
        } else { //4 bit 处理
            re = Integer.parseInt(bitStr, 2);
        }

        return (byte) re;
    }

    public static String byteToBitStr(byte by) {
        return ""
                + (byte) ((by >> 7) & 0x1) + (byte) ((by >> 6) & 0x1)
                + (byte) ((by >> 5) & 0x1) + (byte) ((by >> 4) & 0x1)
                + (byte) ((by >> 3) & 0x1) + (byte) ((by >> 2) & 0x1)
                + (byte) ((by >> 1) & 0x1) + (byte) ((by) & 0x1);
    }

    public static byte[] byteToBitByByteArr(byte by) {
        byte[] bits = new byte[8];
        for (int i = 7; i >= 0; i--) {
            bits[i] = (byte) (by & 1);
            by = (byte) (by >> 1);
        }

        return bits;
    }

    public static byte[] bitsToBytes(byte[] bits) {
        byte[] temp;
        if (bits.length < 8) {
            temp = new byte[8];
            System.arraycopy(bits, 0, temp, 8 - bits.length, bits.length);
        } else {
            temp = bits;
        }
        byte[] bytes = new byte[temp.length / 8];
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < temp.length; i++) {
            sb.append(temp[i]);
            if (sb.length() == 8) {
                bytes[i / 8] = bitStrToByte(sb.toString());
                sb.delete(0, 8);
            }
        }
        return bytes;
    }

    public static byte[] bitsToBytes(String bits) {
        char[] chars = bits.toCharArray();
        byte[] bytes = new byte[chars.length];
        for (int i = 0; i < chars.length; i++) {
            bytes[i] = Byte.parseByte(String.valueOf(chars[i]));
        }
        return bitsToBytes(bytes);
    }


    /**
     * byte to bit array by Boolean array
     *
     * @param by
     * @return
     */
    public static boolean[] byteToBitByBooleanArr(byte by) {
        boolean[] bits = new boolean[8];
        for (int i = 7; i >= 0; i--) {
            bits[i] = (by & 1) == 1;
            by = (byte) (by >> 1);
        }
        return bits;
    }

    /**
     * 字节数组转换成以字节表示为比特的数组
     *
     * @param bytes
     * @return
     */
    public static byte[] bytesToBits(byte[] bytes) {
        byte[] temp = new byte[bytes.length * 8];
        for (int i = 0; i < bytes.length; i++) {
            byte[] bits = byteToBitByByteArr(bytes[i]);
            System.arraycopy(bits, 0, temp, i * 8, 8);
        }
        return temp;
    }

    public static byte[] hexStrToBits(String hex) {
        if (hex.contains("H")) {
            hex = hex.replace("H", "");
        }
        return bytesToBits(ByteUtils.hexToBytes(hex));
    }

    public static String hexStrToBits(String hex, int len) {
        if (hex.contains("H")) {
            hex = hex.replace("H", "");
        }
        byte[] bits = bytesToBits(ByteUtils.hexToBytes(hex));
        int hexLen = hex.length() * 4;
        StringBuilder sb = new StringBuilder();
        if (hexLen >= len) { //取后len位
            for (int i = bits.length - len; i < bits.length; i++) {
                sb.append(bits[i]);
            }
        } else {//前面填充0
            for (int i = 0; i < len - hexLen; i++) {
                sb.append("0");
            }
            for (byte bit : bits) {
                sb.append(bit);
            }
        }
        return sb.toString();
    }


    public static String bitStrToHex(String param) {
        //前面需要填充0的个数
        int remain = param.length() % 8;
        int num = 0;
        if (remain > 0) {
            num = 8 - remain;
        }
        String bits = param;
        if (num > 0) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < num; i++) {
                sb.append(0);
            }
            sb.append(param);
            bits = sb.toString();
        }
        return HexBin.encode(bitsToBytes(bits));
    }

    /**
     * 截取后len位bit
     *
     * @param value
     * @param len
     * @return
     */
    public static String intToBits(int value, int len) {
        StringBuilder sb = new StringBuilder();
        byte[] bits = bytesToBits(Ints.toByteArray(value));
        for (int i = bits.length - len; i < bits.length; i++) {
            sb.append(bits[i]);
        }
        return sb.toString();
    }

}


package jelly.command.coder.util;

import com.google.common.primitives.Ints;

import java.nio.ByteBuffer;
import java.nio.FloatBuffer;

/**
 * @Date 2020/12/23 10:55
 * @Version 1.0
 * @Description
 */
public class ByteUtils {
    private static final char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7',
            '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};



    public static void main(String[] args) {
        System.out.println(revertHex("ABCDDEFH"));
    }

    public static byte[] hexToBytes(String hex) {
        if (hex == null || hex.length() == 0) {
            return null;
        }
        char[] chars = hex.toCharArray();
        byte[] bytes = new byte[chars.length / 2];
        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = (byte) Integer.parseInt("" + chars[i * 2] + chars[i * 2 + 1], 16);
        }
        return bytes;
    }


    public static String bytesToHex(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        StringBuilder hex = new StringBuilder();

        for (byte b : bytes) {
            hex.append(hexDigits[(b >> 4) & 0x0F]);
            hex.append(hexDigits[b & 0x0F]);
        }
        return hex.toString();

    }

    /**
     * 反转
     *
     * @param source
     * @param begin
     * @param length
     * @return
     */
    public static byte[] arraySliceAndReverse(
            byte[] source,
            int begin,
            int length) {
        byte[] tempArr = new byte[source.length];
        System.arraycopy(source, 0, tempArr, 0, source.length);
        byte temp;
        for (int i = 0; i < (source.length - length) / 2; i++) {
            temp = tempArr[begin + i];
            tempArr[begin + i] = tempArr[source.length - i - 1];
            tempArr[source.length - i - 1] = temp;
        }
        return tempArr;
    }


    /**
     * 已测试
     *
     * @param bytes
     * @return
     */
    public static int bytesToInt(byte[] bytes) {
        byte[] temp = new byte[Integer.BYTES];
        if (bytes.length < 4) {
            System.arraycopy(bytes, 0, temp, temp.length - bytes.length, bytes.length);
        } else if (bytes.length > 4) {
            System.arraycopy(bytes, bytes.length - 4, temp, 0, Integer.BYTES);
        }
        return Ints.fromByteArray(temp);
    }

    public static String bytesToString(byte[] bytes, char placeholder) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            if (b == (byte) placeholder) {
                break;
            }
            sb.append((char) b);
        }
        return sb.toString();
    }

    /**
     * String -> bytes array
     *
     * @param param       原字符串
     * @param length      bytes 数组长度
     * @param placeholder 数组空余位置填充
     * @return 字节数组
     */
    public static byte[] stringToBytes(String param, int length, char placeholder) {
        byte[] rawContent = new byte[length];
        char[] array = param.toCharArray();
        int len = Math.min(array.length, length);
        for (int i = 0; i < len; i++) {
            rawContent[i] = (byte) array[i];
        }
        for (int i = array.length; i < length; i++) {
            rawContent[i] = (byte) (placeholder);
        }
        return rawContent;
    }

    public static String revertHex(String hex) {
        StringBuilder sb = new StringBuilder();
        for (int i = hex.length() - 1; i >= 0; i -= 2) {
            sb.append(hex, i - 1, i + 1);
        }
        return sb.toString();
    }

    public static float[] byteArrToFloatArr(byte[] bytes) {
        ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
        FloatBuffer floatBuffer = byteBuffer.asFloatBuffer();
        float[] aFloat = new float[floatBuffer.limit()];
        floatBuffer.get(aFloat);
        return aFloat;
    }

    public static byte[] floatArrToByteArr(float[] floats) {
        ByteBuffer buffer = ByteBuffer.allocate(floats.length * 4);
        FloatBuffer floatBuffer = buffer.asFloatBuffer();
        floatBuffer.put(floats);
        return buffer.array();
    }


}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
Java ,你可以使用 ByteBuffer 类来实现类似于 Python struct 模块pack 和 unpack 方法的功能。以下是一个示例代码: ```javaimport java.nio.ByteBuffer; import java.nio.ByteOrder; public class StructExample { public static void main(String[] args) { // 将 int 值打包为字节序列 int intValue =12345; byte[] packedBytes = packInt(intValue); System.out.println("Packed bytes: " + bytesToHex(packedBytes)); // 将字节序列解包为 int 值 int unpackedInt = unpackInt(packedBytes); System.out.println("Unpacked int: " + unpackedInt); } private static byte[] packInt(int value) { ByteBuffer buffer = ByteBuffer.allocate(4); buffer.order(ByteOrder.LITTLE_ENDIAN); // 设置字节序为小端序列(与Pythonstruct默认相同) buffer.putInt(value); return buffer.array(); } private static int unpackInt(byte[] bytes) { ByteBuffer buffer = ByteBuffer.wrap(bytes); buffer.order(ByteOrder.LITTLE_ENDIAN); // 设置字节序为小端序列 return buffer.getInt(); } private static String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02X", b)); } return sb.toString(); } } ``` 上述代码演示了 Java 如何实现类似于 Pythonstruct 模块pack 和 unpack 方法。`packInt` 方法将一个 int 值打包为字节序列,`unpackInt` 方法将字节序列解包为一个 int 值。在这个示例,我们使用了 ByteBuffer 类来处理字节操作,并通过设置字节序为小端序列来与 Pythonstruct 默认行为保持一致。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值