C# 比较 .NET 中的两个字节数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/43289/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Comparing two byte arrays in .NET
提问by Hafthor
How can I do this fast?
我怎样才能快速做到这一点?
Sure I can do this:
当然我可以这样做:
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;
}
But I'm looking for either a BCLfunction or some highly optimized proven way to do this.
但我正在寻找BCL函数或一些高度优化的行之有效的方法来做到这一点。
java.util.Arrays.equals((sbyte[])(Array)a1, (sbyte[])(Array)a2);
works nicely, but it doesn't look like that would work for x64.
效果很好,但它看起来不适用于 x64。
Note my super-fast answer here.
请注意我在这里的超快速回答。
采纳答案by Hafthor
User gilsuggested unsafe code which spawned this solution:
用户gil建议产生此解决方案的不安全代码:
// Copyright (c) 2008-2013 Hafthor Stefansson
// Distributed under the MIT/X11 software license
// Ref: http://www.opensource.org/licenses/mit-license.php.
static unsafe bool UnsafeCompare(byte[] a1, byte[] a2) {
if(a1==a2) return true;
if(a1==null || a2==null || a1.Length!=a2.Length)
return false;
fixed (byte* p1=a1, p2=a2) {
byte* x1=p1, x2=p2;
int l = a1.Length;
for (int i=0; i < l/8; i++, x1+=8, x2+=8)
if (*((long*)x1) != *((long*)x2)) return false;
if ((l & 4)!=0) { if (*((int*)x1)!=*((int*)x2)) return false; x1+=4; x2+=4; }
if ((l & 2)!=0) { if (*((short*)x1)!=*((short*)x2)) return false; x1+=2; x2+=2; }
if ((l & 1)!=0) if (*((byte*)x1) != *((byte*)x2)) return false;
return true;
}
}
which does 64-bit based comparison for as much of the array as possible. This kind of counts on the fact that the arrays start qword aligned. It'll work if not qword aligned, just not as fast as if it were.
它对尽可能多的数组进行基于 64 位的比较。这种依赖于数组开始 qword 对齐的事实。如果不是 qword 对齐,它会起作用,只是没有它那么快。
It performs about seven timers faster than the simple for
loop. Using the J# library performed equivalently to the original for
loop. Using .SequenceEqual runs around seven times slower; I think just because it is using IEnumerator.MoveNext. I imagine LINQ-based solutions being at least that slow or worse.
它的执行速度比简单for
循环快 7 个定时器。使用 J# 库执行与原始for
循环等效的操作。使用 .SequenceEqual 运行速度大约慢七倍;我认为只是因为它使用的是 IEnumerator.MoveNext。我想基于 LINQ 的解决方案至少会那么慢或更糟。
回答by gil
I would use unsafe code and run the for
loop comparing Int32 pointers.
我会使用不安全的代码并运行for
比较 Int32 指针的循环。
Maybe you should also consider checking the arrays to be non-null.
也许您还应该考虑检查数组是否为非空。
回答by Markus Olsson
Sorry, if you're looking for a managed way you're already doing it correctly and to my knowledge there's no built in method in the BCL for doing this.
抱歉,如果您正在寻找一种托管方式,那么您已经在正确地进行操作,据我所知,BCL 中没有内置方法可以执行此操作。
You should add some initial null checks and then just reuse it as if it where in BCL.
您应该添加一些初始空检查,然后像在 BCL 中一样重用它。
回答by Jason Bunting
If you are not opposed to doing it, you can import the J# assembly "vjslib.dll" and use its Arrays.equals(byte[], byte[]) method...
如果您不反对这样做,则可以导入 J# 程序集“vjslib.dll”并使用其Arrays.equals(byte[], byte[]) 方法...
Don't blame me if someone laughs at you though...
不过,如果有人嘲笑你,请不要怪我......
EDIT: For what little it is worth, I used Reflector to disassemble the code for that, and here is what it looks like:
编辑:对于它的价值,我使用 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;
}
回答by aku
You can use Enumerable.SequenceEqualmethod.
您可以使用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
If you can't use .NET 3.5 for some reason, your method is OK.
Compiler\run-time environment will optimize your loop so you don't need to worry about performance.
如果由于某种原因您不能使用 .NET 3.5,那么您的方法是可以的。
编译器\运行时环境将优化您的循环,因此您无需担心性能。
回答by Milan Gardian
.NET 3.5 and newer have a new public type, System.Data.Linq.Binary
that encapsulates byte[]
. It implements IEquatable<Binary>
that (in effect) compares two byte arrays. Note that System.Data.Linq.Binary
also has implicit conversion operator from byte[]
.
.NET 3.5 和更新版本有一个新的公共类型,System.Data.Linq.Binary
它封装了byte[]
. 它实现IEquatable<Binary>
了(实际上)比较两个字节数组。请注意,System.Data.Linq.Binary
还有来自byte[]
.
MSDN documentation:System.Data.Linq.Binary
MSDN 文档:System.Data.Linq.Binary
Reflector decompile of the Equals method:
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;
}
Interesting twist is that they only proceed to byte-by-byte comparison loop if hashes of the two Binary objects are the same. This, however, comes at the cost of computing the hash in constructor of Binary
objects (by traversing the array with for
loop :-) ).
有趣的是,如果两个 Binary 对象的哈希值相同,它们只会进行逐字节比较循环。然而,这是以在Binary
对象的构造函数中计算散列为代价的(通过for
循环遍历数组:-))。
The above implementation means that in the worst case you may have to traverse the arrays three times: first to compute hash of array1, then to compute hash of array2 and finally (because this is the worst case scenario, lengths and hashes equal) to compare bytes in array1 with bytes in array 2.
上面的实现意味着在最坏的情况下,您可能必须遍历数组 3 次:首先计算 array1 的散列,然后计算 array2 的散列,最后(因为这是最坏的情况,长度和散列相等)进行比较数组 1 中的字节与数组 2 中的字节。
Overall, even though System.Data.Linq.Binary
is built into BCL, I don't think it is the fastest way to compare two byte arrays :-|.
总的来说,即使System.Data.Linq.Binary
内置在 BCL 中,我也不认为这是比较两个字节数组的最快方法:-|。
回答by Mirko Klemm
I thought about block-transfer acceleration methods built into many graphics cards. But then you would have to copy over all the data byte-wise, so this doesn't help you much if you don't want to implement a whole portion of your logic in unmanaged and hardware-dependent code...
我想到了许多显卡内置的块传输加速方法。但是,您将不得不逐字节复制所有数据,因此,如果您不想在非托管和依赖于硬件的代码中实现整个逻辑部分,这对您没有多大帮助......
Another way of optimization similar to the approach shown above would be to store as much of your data as possible in a long[] rather than a byte[] right from the start, for example if you are reading it sequentially from a binary file, or if you use a memory mapped file, read in data as long[] or single long values. Then, your comparison loop will only need 1/8th of the number of iterations it would have to do for a byte[] containing the same amount of data. It is a matter of when and how often you need to compare vs. when and how often you need to access the data in a byte-by-byte manner, e.g. to use it in an API call as a parameter in a method that expects a byte[]. In the end, you only can tell if you really know the use case...
与上述方法类似的另一种优化方法是从一开始就将尽可能多的数据存储在 long[] 而不是 byte[] 中,例如,如果您从二进制文件中顺序读取它,或者,如果您使用内存映射文件,则将数据作为 long[] 或单个 long 值读入。然后,您的比较循环只需要对包含相同数据量的 byte[] 执行的迭代次数的 1/8。这是您需要比较的时间和频率的问题,以及您需要以逐字节的方式访问数据的时间和频率的问题,例如,在 API 调用中将其用作期望的方法中的参数一个字节[]。最后,你只能判断你是否真的了解用例......
回答by Mikael Svenson
If you look at how .NET does string.Equals, you see that it uses a private method called EqualsHelper which has an "unsafe" pointer implementation. .NET Reflectoris your friend to see how things are done internally.
如果您查看 .NET 如何执行 string.Equals,您会发现它使用名为 EqualsHelper 的私有方法,该方法具有“不安全”的指针实现。.NET Reflector是您了解内部工作方式的好帮手。
This can be used as a template for byte array comparison which I did an implementation on in blog post Fast byte array comparison in C#. I also did some rudimentary benchmarks to see when a safe implementation is faster than the unsafe.
这可以用作字节数组比较的模板,我在博客文章Fast byte array compare in C# 中做了一个实现。我还做了一些基本的基准测试,看看什么时候安全的实现比不安全的更快。
That said, unless you really need killer performance, I'd go for a simple fr loop comparison.
也就是说,除非您真的需要出色的性能,否则我会进行简单的 fr 循环比较。
回答by Kevin Driedger
For comparing short byte arrays the following is an interesting hack:
为了比较短字节数组,以下是一个有趣的技巧:
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);
Then I would probably fall out to the solution listed in the question.
然后我可能会遇到问题中列出的解决方案。
It'd be interesting to do a performance analysis of this code.
对这段代码进行性能分析会很有趣。
回答by plinth
P/Invokepowers activate!
P/Invoke力量激活!
[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;
}
回答by user565710
using System.Linq; //SequenceEqual
byte[] ByteArray1 = null;
byte[] ByteArray2 = null;
ByteArray1 = MyFunct1();
ByteArray2 = MyFunct2();
if (ByteArray1.SequenceEqual<byte>(ByteArray2) == true)
{
MessageBox.Show("Match");
}
else
{
MessageBox.Show("Don't match");
}