本文為大家分享了c#利用結(jié)構(gòu)體解析固定格式數(shù)據(jù)的具體代碼,供大家參考,具體內(nèi)容如下
制定了一個通訊協(xié)議,然后其數(shù)據(jù)部分有如下格式。
第三列代表的是字節(jié)數(shù),第4列是數(shù)據(jù)類型。
當(dāng)傳輸或者收到一個byte數(shù)組的時候(下面hex數(shù)據(jù)),按照對應(yīng)格式進(jìn)行解析,解析方法有很多種,網(wǎng)上看到了一種方式是以結(jié)構(gòu)體的方式來解析的,類似c/c++方式。
hex數(shù)據(jù):01 01 00 00 10 44 65 76 69 63 65 20 4e 61 6d 65 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 31 2e 30 2e 30 00 00 00 00 00 00 00 00 00 00 00 41 42 43 31 32 33 34 35 36 37 00 00 00 00 00 00 56 31 2e 30 2e 30 00 00 00 00 00 00 00 00 00 00 32 30 31 38 2f 31 2f 32 32 00 00 00 00 00 00 00
定義一個結(jié)構(gòu)體:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
using system.runtime.interopservices; [structlayoutattribute(layoutkind.sequential, charset = charset.ansi, pack = 1)] public struct infostruct { [marshalas(unmanagedtype.u1, sizeconst = 1)] public byte slotnum; [marshalas(unmanagedtype.u4,sizeconst =4)] public uint32 moduleid; [marshalas(unmanagedtype.byvalarray,sizeconst =32)] public char [] devicename; [marshalas(unmanagedtype.byvalarray, sizeconst = 16)] public char [] hardwarenum; [marshalas(unmanagedtype.byvalarray, sizeconst = 16)] public char [] hardwareversion; [marshalas(unmanagedtype.byvalarray, sizeconst = 16)] public char [] softwareversion; [marshalas(unmanagedtype.byvalarray, sizeconst = 16)] public char [] softwaredate; } |
再寫一個輔助解析的靜態(tài)幫助類,該類提供將結(jié)構(gòu)體轉(zhuǎn)成byte數(shù)組和byte數(shù)組轉(zhuǎn)成結(jié)構(gòu)體功能,我在原來的方法上面添加了泛型,功能不變:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
public static class structhelper { /// <summary> /// byte數(shù)組轉(zhuǎn)目標(biāo)結(jié)構(gòu)體 /// </summary> /// <param name="bytes">byte數(shù)組</param> /// <param name="type">目標(biāo)結(jié)構(gòu)體類型</param> /// <returns>目標(biāo)結(jié)構(gòu)體</returns> public static t bytetostuct<t>( byte [] databuff_) where t: struct { type t = typeof (t); //得到結(jié)構(gòu)體大小 int size = marshal. sizeof (t); //數(shù)組長度小于結(jié)構(gòu)體大小 if (size > databuff_.length) { return default (t); } //分配結(jié)構(gòu)體大小的內(nèi)存空間 intptr structptr = marshal.allochglobal(size); //將byte數(shù)組cpoy到分配好的內(nèi)存空間內(nèi) marshal.copy(databuff_, 0, structptr, size); //將內(nèi)存空間轉(zhuǎn)換為目標(biāo)結(jié)構(gòu)體 t obj = (t)marshal.ptrtostructure(structptr, t); //釋放內(nèi)存空間 marshal.freehglobal(structptr); return obj; } /// <summary> /// 結(jié)構(gòu)體轉(zhuǎn)byte數(shù)組 /// </summary> /// <param name="objstuct">結(jié)構(gòu)體</param> /// <returns>byte數(shù)組</returns> public static byte [] stucttobyte( object objstuct) { //得到結(jié)構(gòu)體大小 int size = marshal. sizeof (objstuct); //創(chuàng)建byte數(shù)組 byte [] bytes = new byte [size]; //分配結(jié)構(gòu)體大小的空間 intptr structptr = marshal.allochglobal(size); //將結(jié)構(gòu)體copy到分配好的內(nèi)存空間內(nèi) marshal.structuretoptr(objstuct, structptr, false ); //從內(nèi)存空間copy到byte數(shù)組 marshal.copy(structptr, bytes, 0, size); //釋放內(nèi)存空間 marshal.freehglobal(structptr); return bytes; } } |
好了現(xiàn)在結(jié)構(gòu)體有了,轉(zhuǎn)換方法也有了那么就來使用一下吧!先將結(jié)構(gòu)體轉(zhuǎn)為byte數(shù)組,然后再還原結(jié)構(gòu)體試試:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
static void main( string [] args) { try { infostruct info; info.hardwarenum = "1.0.0" .tochararray(); info.hardwareversion = "abc1234567" .tochararray(); info.devicename = "device name1" .tochararray(); info.moduleid = 0x10000001; info.slotnum = 1; info.softwaredate = "2018/1/22" .tochararray(); info.softwareversion = "v1.0.0" .tochararray(); var b = structhelper.stucttobyte(info); console.writeline( "struct length:" +b.length); console.writeline( "hex:" +bytetoolshelper.bytearraytohexstring(b, " " )); var s = structhelper.bytetostuct<infostruct>(b); console.writeline( "name:" +s.devicename.getstring()); } catch (exception ex) { console.writeline(ex.message); } console.readkey(); } |
其中bytetoolshelper.bytearraytohexstring是我封裝的一個函數(shù),將byte數(shù)組轉(zhuǎn)為hex字符串,方便顯示和調(diào)試可以不用管。
然后調(diào)試運(yùn)行得到結(jié)果:
我擦,這是什么情況?什么叫“未能封送類型,因?yàn)榍度霐?shù)組實(shí)例的長度與布局中聲明的長度不匹配?????”
調(diào)試一下就可以發(fā)現(xiàn)實(shí)際結(jié)構(gòu)體標(biāo)記的sizeconst和tochararray()函數(shù)得到的長度并不一樣,字符串通過tochararray()得到的長度不足導(dǎo)致出現(xiàn)這個異常。
既然是長度不足,那么就想辦法補(bǔ)足吧。
寫個靜態(tài)擴(kuò)展方法,包含上面的getstring擴(kuò)展方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public static char [] getfixlengthchar( this string s, int length) { char [] chaval = new char [length]; array.copy(s.padright(length, '\0' ).tochararray(), chaval, length); return chaval; } public static string getstring( this char [] cc) { return getstring(cc, true ); } public static string getstring( this char [] cc, bool istrimend) { if (istrimend) { return new string (cc).trimend( '\0' ); } else { return new string (cc); } } |
getfixlengthchar是將字符串轉(zhuǎn)為固定長度char數(shù)組,getstring是從char數(shù)組轉(zhuǎn)為字符串,因?yàn)橛?#39;\0'可以用trimend函數(shù)去掉,這樣字符串后面就不會有一排空的了。
我們再試試結(jié)果:
沒問題!成功的轉(zhuǎn)換和還原了。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:https://www.cnblogs.com/Iamsorry/archive/2018/01/29/8378061.html