比较.NET中的两个字节数组

时间:2020-03-05 18:47:29  来源:igfitidea点击:

我该如何快速完成?

当然,我可以这样做:

static bool ByteArrayCompare(byte[] a1, byte[] a2)
{
    if (a1.Length != a2.Length)
        return false;

    for (int i=0; i<a1.Length; i++)
        if (a1[i]!=a2[i])
            return false;

    return true;
}

但是我正在寻找一种BCL功能或者一些经过高度优化的行之有效的方式来做到这一点。

java.util.Arrays.equals((sbyte[])(Array)a1, (sbyte[])(Array)a2);

效果很好,但是看起来不适用于x64.

在这里记录我的超快速答案。

解决方案

回答

我会使用不安全的代码,并比较Int32指针运行for循环。

也许我们还应该考虑检查数组是否为空。

回答

抱歉,如果我们正在寻找一种托管方式,那么我们已经在正确地进行此操作,据我所知,BCL中没有内置方法可以执行此操作。

我们应该添加一些初始的空检查,然后就像在BCL中一样重复使用它。

回答

如果我们不反对这样做,则可以导入Jassembly" vjslib.dll"并使用其Arrays.equals(byte [],byte [])方法...

如果有人嘲笑你也不要怪我。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

编辑:对于它所值的是什么,我用Reflector来为它反汇编代码,这是它的样子:

public static bool equals(sbyte[] a1, sbyte[] a2)
{
  if (a1 == a2)
  {
    return true;
  }
  if ((a1 != null) && (a2 != null))
  {
    if (a1.Length != a2.Length)
    {
      return false;
    }
    for (int i = 0; i < a1.Length; i++)
    {
      if (a1[i] != a2[i])
      {
        return false;
      }
    }
    return true;
  }
  return false;
}

回答

我们可以使用Enumerable.SequenceEqual方法。

using System;
using System.Linq;
...
var a1 = new int[] { 1, 2, 3};
var a2 = new int[] { 1, 2, 3};
var a3 = new int[] { 1, 2, 4};
var x = a1.SequenceEqual(a2); // true
var y = a1.SequenceEqual(a3); // false

如果由于某种原因无法使用.NET 3.5,则方法可以。
编译器\运行时环境将优化循环,因此我们无需担心性能。

回答

.NET 3.5及更高版本具有一个新的公共类型,即System.Data.Linq.Binary,它封装了byte []。它实现了" IEquatable <Binary>"(实际上是比较两个字节数组)。注意," System.Data.Linq.Binary"还具有" byte []"中的隐式转换运算符。

MSDN文档:System.Data.Linq.Binary

Equals方法的反射器反编译:

private bool EqualsTo(Binary binary)
{
    if (this != binary)
    {
        if (binary == null)
        {
            return false;
        }
        if (this.bytes.Length != binary.bytes.Length)
        {
            return false;
        }
        if (this.hashCode != binary.hashCode)
        {
            return false;
        }
        int index = 0;
        int length = this.bytes.Length;
        while (index < length)
        {
            if (this.bytes[index] != binary.bytes[index])
            {
                return false;
            }
            index++;
        }
    }
    return true;
}

有趣的是,只有当两个Binary对象的哈希相同时,它们才进行逐字节比较循环。但是,这是以在"二进制"对象的构造函数中计算哈希值为代价的(通过使用" for"循环遍历数组:-))。

上面的实现意味着在最坏的情况下,我们可能必须遍历三个数组:首先计算array1的哈希值,然后计算array2的哈希值,最后(因为这是最坏的情况,长度和哈希值相等)进行比较数组1中的字节与数组2中的字节。

总的来说,即使BCL内置了" System.Data.Linq.Binary",我也不认为这是比较两个字节数组:-|的最快方法。

回答

我想到了许多图形卡内置的块传输加速方法。但是随后我们将不得不按字节复制所有数据,因此如果我们不想以不受管且与硬件相关的代码来实现逻辑的整个部分,那么这将无济于事。

与上面显示的方法类似的另一种优化方法是,从一开始就将尽可能多的数据存储在long []中,而不是byte []中,例如,如果我们从二进制文件中顺序读取数据,或者,如果我们使用内存映射文件,则将数据读取为long []或者单个long值。然后,比较循环将只需要对包含相同数据量的byte []执行的迭代次数的1/8.
我们需要比较的时间和频率与何时需要以字节为单位访问数据的时间和频率有关,例如在API调用中将其用作需要byte []的方法中的参数。最后,我们只能告诉我们是否真的知道用例...

回答

如果看一下.NET如何处理string.Equals,我们会发现它使用了一个称为EqualsHelper的私有方法,该方法具有"不安全"的指针实现。 .NET Reflector是朋友,可以了解内部的工作方式。

这可以用作字节数组比较的模板,我在博客文章C#中的快速字节数组比较中做了一个实现。我还做了一些基本的基准测试,以了解安全实施的时间快于不安全实施的时间。

就是说,除非我们真的需要杀手级性能,否则我将进行简单的fr循环比较。

回答

为了比较短字节数组,以下是一个有趣的技巧:

if(myByteArray1.Length != myByteArray2.Length) return false;
if(myByteArray1.Length == 8)
   return BitConverter.ToInt64(myByteArray1, 0) == BitConverter.ToInt64(myByteArray2, 0); 
else if(myByteArray.Length == 4)
   return BitConverter.ToInt32(myByteArray2, 0) == BitConverter.ToInt32(myByteArray2, 0);

然后,我可能会遇到问题中列出的解决方案。

对此代码进行性能分析将很有趣。

回答

P /调用电源激活!

[DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]
static extern int memcmp(byte[] b1, byte[] b2, long count);

static bool ByteArrayCompare(byte[] b1, byte[] b2)
{
    // Validate buffers are the same length.
    // This also ensures that the count does not exceed the length of either buffer.  
    return b1.Length == b2.Length && memcmp(b1, b2, b1.Length) == 0;
}