存储/检索位C#的最佳方式

时间:2013-12-18 05:56:49

标签: c# bit-manipulation

我正在修改现有的C#解决方案,其中数据已经过验证,状态存储如下:

a)给定记录针对某些号码进行验证。条件(比如5)。失败/通过状态由位值表示(0 - 传递; 1 - 失败) b)因此,如果所有5次验证的记录都失败,则值为11111.这将转换为小数并存储在数据库中。

再一次,这个十进制值将被转换回二进制(使用按位和运算符),它将用于显示通过/失败的记录。

问题是,在C#中使用long数据类型来处理小数和'十进制' SQL Server 2008中的数据类型,用于存储此十进制值。最大长转换为二进制的值最多只能保存64位,因此验证计数目前限制为64.

我的要求是删除此限制以允许任何号码。验证。

如何储存大号。比特并检索它们?另外,请记住,这是一个现有的(.NET 2.0)解决方案,不能升级/使用任何第三方库,并且必须最小化更改

最新更新

是的,从应用程序的角度看,这个解决方案似乎没问题,即如果只有I(当前的解决方案)只使用C#。但是,现有解决方案的设计者通过在SQL Server DB中将二进制值(11111表示所有5个记录失败,10111 - 除了第4个记录失败,等等......)转换为十进制而使事情复杂化。 SP取此值为no。记录未通过每次验证。

OPEN sValidateCUR                        
 FETCH NEXT FROM sValidateCUR INTO @ValidationOID,@ValidationBit, @ValidationType            
 WHILE @@FETCH_STATUS = 0                        
 BEGIN                 
 -- Fetch the Error Record Count                
 SET @nBitVal = ABS(RPT.fGetPowerValue(@ValidationBit))  -- Validation bit is no. of a type of validation, say, e.g. 60. So 1st time when loop run, ValidationBit will be 0
select @ErrorRecordCount = COUNT(1) FROM 
 <<Error_Table_Where_Flags_are availble in decimal values>>
          WITH(NOLOCK) WHERE  ExpressionValidationFlags & CAST(CAST(@nBitVal AS VARCHAR(20)) AS Bigint) = CAST(@nBitVal AS VARCHAR(20)) -- For @ValidationBit = 3, @nBitVal = 2^3 = 8

现在,在应用程序中,使用BitArray,我设法在BitArray中存储传递/失败的记录,将其转换为byte []并作为VARBINARY(100)存储在SQL Server中...(同一列ExpressionValidationFlags,这是早期的BIGINT,现在是VARBINARY并保存字节数组)。但是,要完成我的更改,我需要修改上面的SP。

再次,期待寻求帮助!!

由于

3 个答案:

答案 0 :(得分:3)

为什么不使用专门设计的课程 BitArray

http://msdn.microsoft.com/query/dev11.query?appId=Dev11IDEF1&l=EN-US&k=k(System.Collections.BitArray);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5);k(DevLang-csharp)&rd=true

e.g。

  BitArray array = new BitArray(150); // <- up to 150 bits

  ...
  array[140] = true;  // <- set 140th bit 
  array[130] = false; // <- reset 130th bit 
  ...
  if (array[120]) {   // <- if 120th bit is set
    ...

答案 1 :(得分:2)

根据您使用的数据库的限制,有几种方法可以解决这个问题。

如果能够在数据库中存储字节数组,则可以使用BitArray类。您可以将构造函数传递给一个字节数组,使用它来轻松检查并按索引设置每个位,然后使用它内置的CopyTo方法将其复制回字节数组。

示例:

byte[] statusBytes = yourDatabase.Get("passed_failed_bits");
BitArray statusBits = new BitArray(statusBytes);
...
statusBits[65] = false;
statusBits[66] = true;
...
statusBits.CopyTo(statusBytes, 0);
yourDatabase.Set("passed_failed_bits", statusBytes);

如果数据库无法处理原始字节数组,您始终可以将字节数组编码为十六进制字符串:

string hex = BitConverter.ToString(statusBytes);
hex.Replace("-","");

然后再次将其恢复为字节数组:

int numberChars = hex.Length;
byte[] statusBytes= new byte[numberChars / 2];
for (int i = 0; i < numberChars; i += 2) {
    statusBytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}

如果你甚至无法存储字符串,那么有更多创造性的方法可以将字节数组转换为多个long或double。

此外,如果空间效率是一个问题,那么通过使用更多的字符范围而不使用控制字符,还有其他更有效(但更复杂)的方法将字节编码为ascii文本。如果您发现数据在长延伸时保持相同的值,您可能还需要查看运行长度编码字节数组。

希望这有帮助!

答案 2 :(得分:-1)

为什么不使用字符串呢?您可以在数据库中放入大量字符(因为您控制输入,所以使用VARCHAR而不是NVARCHAR。)

使用您的示例,如果您有“11111”,则可以跳过按位操作,只需执行以下操作:

string myBits = "11111";
bool failedPosition0 = myBits[0] == '1';
bool failedPosition1 = myBits[1] == '1';
bool failedPosition2 = myBits[2] == '1';
bool failedPosition3 = myBits[3] == '1';
bool failedPosition4 = myBits[4] == '1';