閑著無聊,寫了一個對象轉(zhuǎn)換成byte[]的工具類,支持整型按位寫入(大大節(jié)省空間),具體步驟如下:
1. 定義實體類和注解
public class User { /** * ID,4個字節(jié),32bit */ @JSONField(ordinal = 1) @BitPos(offset=0,size = 32) public int id; /** * 姓名,10個字節(jié)(80bit) */ @JSONField(ordinal = 2) @BitPos(offset = 32, size= 80) public String name; /** * 性別,0:男,1:女,1Bit */ @JSONField(ordinal = 3) @BitPos(offset = 112, size = 1) public int sex; /** * 年齡,最大127,7Bit */ @JSONField(ordinal = 4) @BitPos(offset = 113, size=7) public int age; /** * 身高,最大2^10-1=1023cm,10Bit */ @JSONField(ordinal = 5) @BitPos(offset = 120, size = 10) public int height; /** * 體重,最大2^10-1=1023kg,10Bit */ @JSONField(ordinal = 6) @BitPos(offset = 130, size = 10) public int weight; /** * 多少個月的薪水,最大2^4-1=15個月薪,4Bit */ @JSONField(ordinal = 7) @BitPos(offset = 140, size=4) public int monthSalary; /** * 地址:20字節(jié),160bit */ @JSONField(ordinal = 8) @BitPos(offset = 144, size = 160) public String address; }
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface BitPos { /** * 位置(占總長度的位置) */ int offset() default -1; /** * 長度(多少bit) */ int size() default -1; }
2. 工具類
package com.hdwang.test.bit; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.serializer.SerializerFeature; import java.io.UnsupportedEncodingException; import java.lang.reflect.Field; /** * 對象轉(zhuǎn)位字節(jié)(整型實現(xiàn)按bit寫入,字符串則按字節(jié)寫入) * * 時間: 2024/1/23 11:12 */ public class ObjToBitBytesUtil { public static void main(String[] args) throws IllegalAccessException, UnsupportedEncodingException { User user = new User(); user.id = 10001; user.name = "張三"; user.sex = 0; user.age = 18; user.height = 170; user.weight = 50; user.monthSalary = 13; user.address = "浙江杭州西湖"; System.out.println("原始對象:"); System.out.println(JSON.toJSONString(user, SerializerFeature.WriteNullStringAsEmpty)); //對象寫成字節(jié)數(shù)組 byte[] bytes = writeObjToBitBytes(user, 38); System.out.println("對象的字節(jié)數(shù)組16進制表示:"); printHex(bytes); //字節(jié)數(shù)組轉(zhuǎn)成對象 User readUser = readBitBytesToObj(bytes); System.out.println("字節(jié)數(shù)組轉(zhuǎn)換成的對象:"); System.out.println(JSON.toJSONString(readUser,SerializerFeature.WriteNullStringAsEmpty)); } private static User readBitBytesToObj(byte[] bytes) throws IllegalAccessException, UnsupportedEncodingException { User user = new User(); Field[] fields = user.getClass().getFields(); for (Field field : fields) { BitPos bitPos = field.getAnnotation(BitPos.class); Object val = readField(bytes, field, bitPos.offset(), bitPos.size()); field.set(user,val); } return user; } private static Object readField(byte[] buffer, Field field, int offset, int size) throws UnsupportedEncodingException { Object val = null; if(field.getType().equals(int.class) || field.getType().equals(Integer.class)){ // 整型,按位讀取 int valInt = 0; //起始緩存位置(第幾個字節(jié),從0開始) int startBufferIndex = offset / 8; //起始字節(jié)已經(jīng)占用了多少bit int startByteUsedBit = offset % 8; //起始字節(jié)需要讀取多少bit(默認剩余bit全部讀取) int startByteReadBit = 8 - startByteUsedBit; if(size < startByteReadBit){ //需要讀取的bit數(shù)少,重置為實際需要讀取的bit數(shù) startByteReadBit = size; } //結(jié)束緩存位置(第幾個字節(jié)) int endBufferIndex = (offset + size - 1) / 8; int endByteUseBit = ((offset + size - 1) % 8)+1; // 緩存間隔位置(緩存起止位置之間的間隔字節(jié)數(shù)) int gapByteCount = endBufferIndex - startBufferIndex - 1; // 1. 讀取起始字節(jié)(讀高位) byte lowerByte = buffer[startBufferIndex]; lowerByte = (byte) (lowerByte >>> startByteUsedBit); int mask = (1 << startByteReadBit) - 1; valInt = lowerByte & mask; // 2. 讀取中間字節(jié)(讀整個字節(jié)) if(gapByteCount > 0) { for (int i = 0; i < gapByteCount; i++) { int leftMove = startByteReadBit + (i * 8); byte b = buffer[startBufferIndex+(i+1)]; valInt |= (b << leftMove); } } // 3. 讀取結(jié)束字節(jié)(讀取低位) if(endBufferIndex > startBufferIndex) { byte b = buffer[endBufferIndex]; int leftMove = startByteReadBit + gapByteCount * 8; mask = (1 << endByteUseBit) - 1; valInt |= ((b & mask) << leftMove); } val = valInt; }else{ // 字符串按字節(jié)讀取 byte[] bytes = new byte[size/8]; int startBufferIndex = offset / 8; for(int i=0;i< bytes.length;i++){ bytes[i] = buffer[startBufferIndex++]; } String valStr = new String(bytes,"utf-8"); val = valStr; } return val; } private static byte[] writeObjToBitBytes(User user, int bufferSize) throws IllegalAccessException, UnsupportedEncodingException { byte[] buffer = new byte[bufferSize]; Field[] fields = user.getClass().getFields(); for (Field field : fields) { BitPos bitPos = field.getAnnotation(BitPos.class); Object val = field.get(user); writeField(buffer, val, bitPos.offset(), bitPos.size()); } return buffer; } private static void writeField(byte[] buffer, Object val, int offset, int size) throws UnsupportedEncodingException { if (val instanceof Integer) { // 整型,按位寫入 int valInt = (int) val; //起始緩存位置(第幾個字節(jié),從0開始) int startBufferIndex = offset / 8; //起始字節(jié)已經(jīng)占用了多少bit int startByteUsedBit = offset % 8; //起始字節(jié)需要寫入多少bit(默認剩余bit全部寫入) int startByteWriteBit = 8 - startByteUsedBit; if(size < startByteWriteBit){ //需要寫入的bit數(shù)少,重置為實際需要寫入的bit數(shù) startByteWriteBit = size; } //結(jié)束緩存位置(第幾個字節(jié)) int endBufferIndex = (offset + size - 1) / 8; int endByteUseBit = ((offset + size - 1) % 8)+1; // 緩存間隔位置(緩存起止位置之間的間隔字節(jié)數(shù)) int gapByteCount = endBufferIndex - startBufferIndex - 1; // 1. 寫入起始字節(jié)(之前在低位可能已經(jīng)存在值了,現(xiàn)在寫入的寫到高位去) int mask = (1 << startByteWriteBit) - 1; //取低startByteWriteBit位,左移startByteUsedBit位,與原來的值或操作即可寫入高位 buffer[startBufferIndex] |= ((valInt & mask) << startByteUsedBit); // 2. 寫中間字節(jié)(全字節(jié)寫入) if(gapByteCount > 0) { for (int i = 0; i < gapByteCount; i++) { int rightMove = startByteWriteBit + (i * 8); buffer[startBufferIndex+(i+1)] = (byte) ((valInt >> rightMove) & 0xFF); } } // 3. 寫結(jié)束字節(jié)(寫入低位即可) if(endBufferIndex > startBufferIndex) { int rightMove = startByteWriteBit + gapByteCount * 8; mask = (1 << endByteUseBit) - 1; buffer[endBufferIndex] = (byte) ((valInt >> rightMove) & mask); } } else { // 字符串直接按字節(jié)寫入 byte[] bytes = val.toString().getBytes("utf-8"); int actualByteCount = bytes.length; int startBufferIndex = offset / 8; int endBufferIndex = startBufferIndex + size/8-1; int byteIndex = 0; for(int i = startBufferIndex; i<=endBufferIndex; i++) { if(byteIndex <= actualByteCount-1) { buffer[i] = bytes[byteIndex++]; }else{ //補空格 buffer[i] = ' '; } } } } private static void printHex(byte[] byteArray) { for (byte b : byteArray) { // 將每個字節(jié)轉(zhuǎn)換為16進制字符串 String hex = String.format("%02X", b); System.out.print(hex + " "); } System.out.println(); } }
?
?
3. 測試結(jié)果
原始對象: {"id":10001,"name":"張三","sex":0,"age":18,"height":170,"weight":50,"monthSalary":13,"address":"浙江杭州西湖"} 對象的字節(jié)數(shù)組16進制表示: 11 27 00 00 E5 BC A0 E4 B8 89 20 20 20 20 24 AA C8 D0 E6 B5 99 E6 B1 9F E6 9D AD E5 B7 9E E8 A5 BF E6 B9 96 20 20 字節(jié)數(shù)組轉(zhuǎn)換成的對象: {"id":10001,"name":"張三 ","sex":0,"age":18,"height":170,"weight":50,"monthSalary":13,"address":"浙江杭州西湖 "}
?
?
參考文章:文章來源:http://www.zghlxwxcb.cn/news/detail-818966.html
https://www.cnblogs.com/Dotnet9-com/p/17981055文章來源地址http://www.zghlxwxcb.cn/news/detail-818966.html
到了這里,關(guān)于實現(xiàn)對象轉(zhuǎn)成字節(jié)數(shù)組(整型支持按位寫入,字符串則按字節(jié)寫入)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!