java:bytes[]转long的三种方式

来源:互联网 发布:电商java 编辑:程序博客网 时间:2024/05/22 06:19

bytes[] 到数字类型的转换是个经常用到的代码,解决方式也不止一种,最近需要将bytes[]转为long,有机会深入了解了一下,此文做个总结。

java代码实现

如果不想借助任何已经有的类,完全可以自己实现这段代码,如下:

    /**     * 将字节数组转为long<br>     * 如果input为null,或offset指定的剩余数组长度不足8字节则抛出异常     * @param input      * @param offset 起始偏移量     * @param littleEndian 输入数组是否小端模式     * @return     */    public static long longFrom8Bytes(byte[] input, int offset, boolean littleEndian){        long value=0;        // 循环读取每个字节通过移位运算完成long的8个字节拼装        for(int  count=0;count<8;++count){            int shift=(littleEndian?count:(7-count))<<3;            value |=((long)0xff<< shift) & ((long)input[offset+count] << shift);        }        return value;    }

借助java.nio.ByteBuffer实现

java.nio.ByteBuffer 本身就有getLong,getInt,getFloat….方法,只要将byte[]转换为ByteBuffer就可以实现所有primitive类型的数据读取,参见javadoc。

    /**     * 利用 {@link java.nio.ByteBuffer}实现byte[]转long     * @param input     * @param offset      * @param littleEndian 输入数组是否小端模式     * @return     */    public static long bytesToLong(byte[] input, int offset, boolean littleEndian) {         // 将byte[] 封装为 ByteBuffer         ByteBuffer buffer = ByteBuffer.wrap(input,offset,8);        if(littleEndian){            // ByteBuffer.order(ByteOrder) 方法指定字节序,即大小端模式(BIG_ENDIAN/LITTLE_ENDIAN)            // ByteBuffer 默认为大端(BIG_ENDIAN)模式             buffer.order(ByteOrder.LITTLE_ENDIAN);        }        return buffer.getLong();      } 

借助java.io.DataInputStream实现

java.io.DataInputStream 同样提供了readLong,readLong,readLong….方法,只要将byte[]转换为DataInputStream就可以实现所有primitive类型的数据读取,参见javadoc。

完整测试代码

下面的Junit 测试代码计算String 的MD5校验码(16 bytes),然后使用上述方式分别将16 bytes转换为2个long(大端模式)然后以16进制模式输出结果,以验证三种方式一致性。

package net.gdface.facelog;import java.io.ByteArrayInputStream;import java.io.DataInputStream;import java.io.IOException;import java.nio.ByteBuffer;import java.nio.ByteOrder;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import org.junit.Test;public class TestSerialVersionUID {    /**     * 生成MD5校验码     *      * @param source     * @return     */    static public byte[] getMD5(byte[] source) {        if (null==source)            return null;        try {            MessageDigest md = MessageDigest.getInstance("MD5");            return md.digest(source);        } catch (NoSuchAlgorithmException e) {            e.printStackTrace();        }        return null;    }    /**     * 将16位byte[] 转换为32位的HEX格式的字符串String     *      * @param buffer     * @return     */    static public String toHex(byte buffer[]) {        if (null==buffer)            return null;        StringBuffer sb = new StringBuffer(buffer.length * 2);        for (int i = 0; i < buffer.length; i++) {            sb.append(Character.forDigit((buffer[i] & 240) >> 4, 16));            sb.append(Character.forDigit(buffer[i] & 15, 16));        }        return sb.toString();    }    /**     * 将字节数组转为long<br>     * 如果input为null,或offset指定的剩余数组长度不足8字节则抛出异常     * @param input      * @param offset 起始偏移量     * @param littleEndian 输入数组是否小端模式     * @return     */    public static long longFrom8Bytes(byte[] input, int offset, boolean littleEndian){        if(offset <0 || offset+8>input.length)            throw new IllegalArgumentException(String.format("less than 8 bytes from index %d  is insufficient for long",offset));        long value=0;        for(int  count=0;count<8;++count){            int shift=(littleEndian?count:(7-count))<<3;            value |=((long)0xff<< shift) & ((long)input[offset+count] << shift);        }        return value;    }    /**     * 利用 {@link java.nio.ByteBuffer}实现byte[]转long     * @param input     * @param offset      * @param littleEndian 输入数组是否小端模式     * @return     */    public static long bytesToLong(byte[] input, int offset, boolean littleEndian) {         if(offset <0 || offset+8>input.length)            throw new IllegalArgumentException(String.format("less than 8 bytes from index %d  is insufficient for long",offset));        ByteBuffer buffer = ByteBuffer.wrap(input,offset,8);        if(littleEndian){            // ByteBuffer.order(ByteOrder) 方法指定字节序,即大小端模式(BIG_ENDIAN/LITTLE_ENDIAN)            // ByteBuffer 默认为大端(BIG_ENDIAN)模式             buffer.order(ByteOrder.LITTLE_ENDIAN);        }        return buffer.getLong();      }     @Test    public void test() throws IOException {        String input="net.gdface.facelog.dborm.person.FlPersonBeanBase";        byte[] md5 = getMD5(input.getBytes());        System.out.printf("md5 [%s]\n",toHex(md5));        // 三种方式运算结果对比验证        DataInputStream dataInput = new DataInputStream(new ByteArrayInputStream(md5));         long l1 = dataInput.readLong();        long l2 = dataInput.readLong();        System.out.printf("l1=0x%x l2=0x%x,DataInputStream\n", l1,l2);        long ln1 = bytesToLong(md5,0, false);        long ln2 = bytesToLong(md5,8, false);        System.out.printf("ln1=0x%x ln2=0x%x,ByteBuffer\n", ln1,ln2);        long ll1 = longFrom8Bytes(md5,0, false);        long ll2 = longFrom8Bytes(md5,8, false);            System.out.printf("ll1=0x%x ll2=0x%x\n", ll1,ll2);    }}

输出结果

md5 [39627933ceeebf2740e1f822921f5837]
l1=0x39627933ceeebf27 l2=0x40e1f822921f5837,DataInputStream
ln1=0x39627933ceeebf27 ln2=0x40e1f822921f5837,,ByteBuffer
ll1=0x39627933ceeebf27 ll2=0x40e1f822921f5837

参考资料

《Java 中 byte、byte 数组和 int、long 之间的转换》

阅读全文
0 0
原创粉丝点击