一.背景说明
工作中经常遇到解析二进制文件,一般协议是由甲乙双方共同制定。因为项目周期长,变更总是无法避免;所以初始设计与实现可能存在偏差。
1.统一的编码格式(ASCII 、Unicode、UTF8),未必统一
2.不同语言,基本数据类型所占长度(int32、int64等),接收语言可变
3.同一个地址值可变
二.如何应对
为了应对这样的不断迭代调整,需要配置设计灵活。解析结果往往是基本类型或者是一个对象,我以泛型代替
public class UnitModel<T>where T:new()
{
public int startAdr { get; set; } //起地址
public int index { get; set; } //位号
public int length { get; set; } //字节长度
public string order { get; set; } //顺序 "ABCD" "DCBA"
public string orderBit { get; set; } //顺序 "AB" "BA"
public string type { get; set; } //类型
public string codetype { get; set; } //编码格式
public T value { get; set; } //值
}
一个地址的解析通过上方来完成,本想写成枚举类型。
public class Decompose<T>
{
public UnitModel<T> Analyse(Byte[] bytes, UnitModel<T> t)
{
Byte[] bs = bytes.Skip(t.startAdr).Take(t.length).ToArray();
bs = Order(bs, t);//字节顺序
bs = OrderBit(bs, t);//字内bit顺序
return Return(bs,t); //字符串区分编码,类型不区分
}
private UnitModel<T> Return(Byte[] bs, UnitModel<T> t)
{
switch (t.type)
{
case "bit":
t.value = ReturnBit(bs, t);
return t;
case "int":
t.value= ReturnInt32(bs, t);
return t;
case "string":
t.value= ReturnString(bs, t);
return t;
case "double":
t.value = ReturnDouble(bs, t);
return t;
case "float":
t.value = ReturnDouble(bs, t);
return t;
}
return t;
}
private string ReturnString(byte[] bs, UnitModel<T> t)
{
switch (t.codetype)
{
case "ASCII":
return Encoding.ASCII.GetString(bs);
case "Unicode":
return Encoding.Unicode.GetString(bs);
case "UTF8":
return Encoding.UTF8.GetString(bs);
}
return "";
}
/// <summary>
/// 返回位
/// </summary>
/// <param name="bs"></param>
/// <param name="t"></param>
/// <returns></returns>
private bool ReturnBit(Byte[] bs, UnitModel<T> t)
{
string s ="";
for (int i = 0;i < bs.Length; i++)
{
s += System.Convert.ToString(bs[i], 2).PadLeft(8, '0'); //!-- 先转换成二进制
}
if(s[t.index]==0)
{
return false;
}
return true;
}
/// <summary>
/// 返回 int型
/// </summary>
/// <param name="bs"></param>
/// <param name="t"></param>
/// <returns></returns>
private int ReturnInt32(Byte[] bs, UnitModel<T> t)
{
switch (t.length)
{
case 4:
return BitConverter.ToInt32(bs, 0);
case 2:
return ReturnInt32MakeUp(bs, t);
case 1:
return ReturnInt32MakeUp(bs, t);
}
return 0;
}
/// <summary>
/// 高位补O
/// </summary>
/// <param name="bs"></param>
/// <param name="t"></param>
/// <returns></returns>
private int ReturnInt32MakeUp(Byte[] bs, UnitModel<T> t)
{
byte[] byteArray = new byte[4];
for (int m =0; m < t.length; m++)
{
byteArray[m] = bs[m];
}
return BitConverter.ToInt32(byteArray, 0);
}
/// <summary>
/// 暂无3个字节的处理方式
/// </summary>
/// <param name="bs"></param>
/// <param name="t"></param>
/// <returns></returns>
private double ReturnDouble(Byte[] bs, UnitModel<T> t)
{
switch (t.length)
{
case 8:
return BitConverter.ToDouble(bs, 0);
case 4:
return ReturnDoubleMakeUp(bs, t);
case 1:
return Convert.ToDouble(bs[0]);
}
return 0;
}
/// <summary>
/// float转double
/// </summary>
/// <param name="bs"></param>
/// <param name="t"></param>
/// <returns></returns>
private double ReturnDoubleMakeUp(Byte[] bs, UnitModel<T> t)
{
return Convert.ToDouble( BitConverter.ToSingle (bs, 0));
}
/// <summary>
/// 高低位的问题
/// </summary>
/// <param name="bs"></param>
/// <param name="t"></param>
/// <returns></returns>
private Byte[] OrderBit(Byte[] bs, UnitModel<T> t)
{
switch (t.codetype)
{
case "AB":
return bs;
case "BA":
for (int i = 0; i < bs.Length; i++)
{
string s = System.Convert.ToString(bs[i], 2).PadLeft(8, '0'); //!-- 先转换成二进制
string tmpS = "";
for (int j = s.Length - 1; j < 0; j--)
{
tmpS += s[j];
}
bs[i] = System.Convert.ToByte(tmpS, 2);
}
return bs;
}
return null;
}
/// <summary>
/// 顺序问题
/// </summary>
/// <param name="bs"></param>
/// <param name="t"></param>
/// <returns></returns>
private Byte[] Order(Byte[] bs, UnitModel<T> t)
{
switch (t.order)
{
case "ABCD":
return bs;
case "DCBA":
Array.Reverse(bs);
return bs;
}
return null;
}
}
一个地址对应一个Model<T>,一个数据包分折成多个值。