字节数组格式化解析
2019-12-01 本文已影响0人
triplestudio
1. 一些实用工具方法
有足够便捷的工具方法,则在用代码表达思想时会变得如鱼得水,一气呵成!
public class ByteHelper
{
public static string BytesToHexString(byte[] bytes)
{
return BytesToHexString(bytes, " ");
}
public static string BytesToHexString(byte[] bytes, string span)
{
StringBuilder sb = new StringBuilder(bytes.Length * (2 + span.Length));
bool isFirst = true;
foreach (byte b in bytes)
{
if (isFirst)
{
isFirst = false;
}
else
{
sb.Append(span);
}
sb.Append(Convert.ToString(b, 16).PadLeft(2, '0').ToUpper());
}
return sb.ToString();
}
public static byte[] HexStringToBytes(string hexString)
{
hexString = hexString.Replace(" ", "");
if ((hexString.Length % 2) != 0)
hexString += " ";
byte[] returnBytes = new byte[hexString.Length / 2];
for (int i = 0; i < returnBytes.Length; i++)
returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2).Replace(" ", ""), 16);
return returnBytes;
}
/// <summary>
/// 字节数组转整型
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
public static int GetIntValue(byte[] bytes)
{
return Convert.ToInt32(GetLongValue(bytes));
}
public static uint GetUnsignedIntValue(byte[] bytes)
{
return Convert.ToUInt32(GetUnsingedLongValue(bytes));
}
/// <summary>
/// 将整型按小端转换成指定长度的byte数组
/// </summary>
/// <param name="value"></param>
/// <param name="len"></param>
/// <returns></returns>
public static byte[] IntToBytes(int value, int len)
{
byte[] bytes = new byte[len];
string strHexValue = Convert.ToString(value, 16).PadLeft(len * 2, '0');
for (int index = 0; index < len; index++)
{
bytes[index] = Convert.ToByte(strHexValue.Substring(strHexValue.Length - (index + 1) * 2, 2), 16);
}
return bytes;
}
public static byte[] SubBytes(byte[] bytes, int startIndex, int len)
{
if (startIndex + len > bytes.Length) len = bytes.Length - startIndex;
byte[] subBytes = new byte[len];
Array.Copy(bytes, startIndex, subBytes, 0, len);
return subBytes;
}
# region 以长整型支持最多 8 个字节的整数转换
/// <summary>
/// 非 1,2,4,8 字节的其它字节转换
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
public static long GetIrregularLongValue(byte[] bytes)
{
long value = 0; // 循环读取每个字节通过移位运算完成long的4个字节拼装
for (int count = 0; count < bytes.Length; ++count)
{
int shift = count << 3;
value |= ((long)0xff << shift) & ((long)bytes[count] << shift);
}
return value;
}
/// <summary>
/// 只考虑小端(有符号)
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
public static long GetLongValue(byte[] bytes)
{
if (bytes.Length == 1)
{
return (long)((sbyte)bytes[0]);
}
else if (bytes.Length == 2)
{
return (long)BitConverter.ToInt16(bytes, 0);
}
else if (bytes.Length == 4)
{
return (long)BitConverter.ToInt32(bytes, 0);
}
else if (bytes.Length == 8)
{
return (long)BitConverter.ToInt64(bytes, 0);
}
return GetIrregularLongValue(bytes);
}
/// <summary>
/// 只考虑小端(无符号)
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
public static ulong GetUnsingedLongValue(byte[] bytes)
{
if (bytes.Length == 1)
{
return (ulong)bytes[0];
}
else if (bytes.Length == 2)
{
return (ulong)BitConverter.ToUInt16(bytes, 0);
}
else if (bytes.Length == 4)
{
return (ulong)BitConverter.ToUInt32(bytes, 0);
}
else if (bytes.Length == 8)
{
return (ulong)BitConverter.ToUInt64(bytes, 0);
}
return (ulong)GetIrregularLongValue(bytes);
}
#endregion
}
2. 配置定义
通过配置来达到动态解析的目的。
配置项通过包括几个方面:
(1)控制解析的基础配置
(2)业务需要的必要配置
(3)其它扩展的配置(如样式控制等)
{
"数据结构":[
{ "长度":4, "标签":"温度","类型":"浮点型","大小端":"大","单位":"℃" },
{ "长度":4, "标签":"湿度","类型":"浮点型","大小端":"大","单位":"%" },
{ "长度":4, "标签":"露点","类型":"浮点型","大小端":"大","单位":"℃" },
],
}
3. 解析数据
/// <summary>
/// 解析数据
/// 根据配置:"长度":2, "标签":"距离","类型":"整型","大小端":"大","单位":"m"
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static JObject ParseData(byte[] data)
{
JObject result = new JObject();
JArray values = new JArray();
JArray items = GetStructConfig().Value<JArray>("数据结构");
int startIndex = 0;
foreach (JObject item in items)
{
if (startIndex >= data.Length) return null;
JObject valueItem = new JObject();
int len = item.Value<int>("长度");
string label = item.Value<string>("标签");
string type = item.Value<string>("类型");
string begin = item.Value<string>("大小端");
string unit = item.Value<string>("单位");
valueItem["label"] = label;
byte[] bs = ByteHelper.SubBytes(data, startIndex, len);
if ("整型".Equals(type))
{
if ("大".Equals(begin))
{
Array.Reverse(bs);
}
valueItem["value"] = ByteHelper.GetIntValue(bs);
}
else if ("浮点型".Equals(type))
{
if ("大".Equals(begin))
{
Array.Reverse(bs);
}
valueItem["value"] = Math.Round(BitConverter.ToSingle(bs, 0), 2);
}
else if ("字符型".Equals(type))
{
valueItem["value"] = Encoding.Default.GetString(bs);
}
else
{
valueItem["value"] = ByteHelper.BytesToHexString(bs);
}
valueItem["label"] = label;
valueItem["unit"] = unit;
values.Add(valueItem);
startIndex += len;
}
result["values"] = values;
return result;
}
}