C#Byte 到BCD,BCD到INT

我有一个由CashRegister Machine创建的Hex文件。 我必须阅读此文件。

文件使用下面详述的格式。 它就像套接字数据包。

代码数据:2个字节
PLU代码数据:7字节
单价数据:5字节
数量数据:5个字节
总金额数据:5字节
PLU名称数据:18字节
税率数据:1字节
长度:24 + 19 Byte

  • PLU代码格式是BCD
  • 单价1-9999999999(BCD)
  • 数量1-9999999999(BCD最后3个数字应为十进制)
  • 总金额1-9999999999(BCD)

我用二进制读取器读取hex文件,然后在Unit Price字节数组中插入int。

byte[] bytes = { data[21], data[22], data[23], data[24], data[25] }; // BCD Byte Array 

这个数组是单价。 但是,如何将此数字转换为十进制数。 并且信息说数量:BCD最后一个数字应该是十进制 – 这是什么意思? 谢谢。

BCD编号将0-9的值编码为4位。 在打包的BCD(可能是你正在处理的)中,一个字节用于包含两个值0-9,每个字节的半字节(4位)中有一个。 要转换为int,你必须做一点点摆弄。 例如,以下内容将BCD字节数组转换为int,最多可容纳9位数字。 如果您的输入数量超过9 bcd,请使用long。

 // assume byte[] bcds is input int result = 0; foreach(byte bcd in bcds) { result *= 100; result += (10 * (bcd >> 4)); result += bcd & 0xf; } 

这假设每个字节都存储为大端BCD,其中最高有效位在字节的最高有效半字节中。 这就是维基百科页面中描述的BCD作为更常见的实现。 如果您正在处理little-endian BCD,那么for循环中的转换代码将是

  result *= 100; result += (10 * (bcd & 0xf)); result += bcd >> 4; 

您还需要确保数组具有正确的字节顺序,即数组中的第一个字节是否包含最重要的两位数,或最不重要的两位数。 例如,使用压缩BCD,数字123456将适合3个字节。 字节[0]或字节[2]中是12吗? 如果您的字节顺序与我的假设不同,您需要调整上面的循环以反转顺序。 我假设12是在byte [0](大端,最左边的字节中有最高位)。

至于描述为BCD和十进制的数量,我需要查看实际值以了解他们正在谈论的内容。

每个字节是两个十进制数字,每个半字节一个。 如果将字节显示为hex,则可以轻松读取数字。

 0x08 0x27 0x42 0x17 0x75 = 827,421,775 

你可以得到像这样的高和低半字节:

 int high = currentByte >> 4; int low = currentByte & 0xF; 

将每个字节转换为数字,如下所示:

 int number = 10 * high + low; 

但请记住,每个字节比下一个字节大100倍。

如果数量为3位小数,只需将最终数字除以1,000即可得到实际值。

正确的代码:

 // assume byte[] bcds is input int result = 0; foreach(byte bcd in bcds) { result *= 100; result += (10 * (bcd >> 4)); result += bcd & 0xf; } 

您还可以通过创建公共静态类来创建byte []的自定义扩展:

 public static class BitConverterExtension { public static UInt64 FromBCDToExtUInt64(this byte[] b, byte[] bcds, uint nBytes, uint startOf) { UInt64 result = 0; uint i = 0; for (i = 0; i < nBytes; i++) { result *= 100; result += (UInt64)(10 * (bcds[startOf + i] >> 4)); result += (UInt64)(bcds[startOf + i] & 0xf); } return (result); } } 

对于这个问题,我的回答可能有点迟,但这是我如何解决这个问题:

1-首先,我需要找到数字的长度,例如:3422 – > 4,100 – > 3

 public static class NumbersUtility { public static int FindNumberLength(int number) { return Convert.ToInt32( Math.Floor(Math.Log(number,10))+1); } public static int FindNumberDivisor(int number) { return Convert.ToInt32(Math.Pow(10, FindNumberLength(number)-1)); } public static int[] FindNumberElements(int number) { int[] elements = new int[FindNumberLength(number)]; int divisor = FindNumberDivisor(number); for (int i = 0; i < elements.Length; i++) { elements[i] = number/divisor; number %= divisor; divisor /= 10; } return elements; } } 

之后我将数字拆分成一个数组,这样可以更容易地遍历和处理数字。 但有一点需要注意,如果数字是奇数长度,则必须将零添加到数组的开头。

  public static byte[] IntToBCD(int[] input, bool isLittleEndian = false) { byte[] outArr = new byte[Convert.ToInt32(Math.Ceiling((double) input.Length/2))]; //Handle the case of an odd number in which a zero should be added at the beginning if (input.Length%2 != 0) { //Use a temp array to expand the old one, you can use lists or //anyother datastructure if you wish to int[] newInput = new int[input.Length+1]; Array.Copy(input,0,newInput,1,input.Length); newInput[0] = 0; input = newInput; //Dispose the temp array newInput = null; } for (int i = 0; i < outArr.Length; i++) { outArr[i]=(byte)(input[i*2]<<4); outArr[i]|=(byte)(input[i*2+1]); } return outArr; }