初始化一个字节数组到一个特定的值,而不是默认的空值?

我忙于用C ++重写一个旧的项目,C#。

我的任务是重写程序,使其function尽可能接近原始。

在一堆文件处理过程中,编写这个程序的以前的开发人员创build了一个包含大量字段的结构,这些字段对应于文件必须写入的设置格式,所以所有这些工作已经完成了。

这些字段都是字节数组。 C ++代码然后使用memset将整个结构设置为所有空格字符( 0x20 )。 一行代码。 简单。

这是非常重要的,因为该文件最终要使用的实用程序正在期待这种格式的文件。 我所要做的就是把这个结构体改为C#中的一个类,但是我找不到一种方法来简单地将这些字节数组初始化为所有的空格字符。

我最终要做的是在类的构造函数中:

 //Initialize all of the variables to spaces. int index = 0; foreach (byte b in UserCode) { UserCode[index] = 0x20; index++; } 

这工作正常,但我确定必须有一个更简单的方法来做到这一点。 在构造函数中将数组设置为UserCode = new byte[6] ,字节数组会自动初始化为默认的空值。 难道我没有办法使它成为声明中的所有空间,所以当我打电话给我的类的构造函数,它是这样直接初始化? 或者一些memset的函数?

对于小型数组,使用数组初始化语法:

 var sevenItems = new byte[] { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; 

对于较大的数组,使用循环的标准。 这是做到这一点最可读和高效的方式:

 var sevenThousandItems = new byte[7000]; for (int i = 0; i < sevenThousandItems.Length; i++) { sevenThousandItems[i] = 0x20; } 

当然,如果你需要做很多事情,那么你可以创build一个帮助程序来帮助保持代码的简洁:

 byte[] sevenItems = CreateSpecialByteArray(7); byte[] sevenThousandItems = CreateSpecialByteArray(7000); // ... public static byte[] CreateSpecialByteArray(int length) { var arr = new byte[length]; for (int i = 0; i < arr.Length; i++) { arr[i] = 0x20; } return arr; } 

使用它来首先创build数组:

 byte[] array = Enumerable.Repeat((byte)0x20, <number of elements>).ToArray(); 

用所需的数组大小replace<number of elements>

您可以使用Enumerable.Repeat()

100个项目的数组初始化为0x20:

 byte[] arr1 = Enumerable.Repeat(0x20,100).ToArray(); 
 var array = Encoding.ASCII.GetBytes(new string(' ', 100)); 

如果你需要初始化一个小数组,可以使用:

 byte[] smallArray = new byte[] { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; 

如果你有一个更大的arrays,那么你可以使用:

 byte[] bitBiggerArray Enumerable.Repeat(0x20, 7000).ToArray(); 

这是简单的,容易下一个男生/女生阅读。 而且99.9%的时间会够快。 (通常将是BestOption™)

但是,如果你真的需要超级速度,使用P / invoke调用优化的memset方法是适合你的:(这里包装了一个很好用的类)

 public static class Superfast { [DllImport("msvcrt.dll", EntryPoint = "memset", CallingConvention = CallingConvention.Cdecl, SetLastError = false)] private static extern IntPtr MemSet(IntPtr dest, int c, int count); //If you need super speed, calling out to M$ memset optimized method using P/invoke public static byte[] InitByteArray(byte fillWith, int size) { byte[] arrayBytes = new byte[size]; GCHandle gch = GCHandle.Alloc(arrayBytes, GCHandleType.Pinned); MemSet(gch.AddrOfPinnedObject(), fillWith, arrayBytes.Length); return arrayBytes; } } 

用法:

 byte[] oneofManyBigArrays = Superfast.InitByteArray(0x20,700000); 

在我之前的人给你你的答案。 我只想指出你滥用foreach循环。 看,因为你必须增加索引标准“for循环”将不仅更紧凑,而且更有效率(“foreach”做了许多事情):

 for (int index = 0; index < UserCode.Length; ++index) { UserCode[index] = 0x20; } 

也许这些可能有帮助?

什么是在C#中的memset相当于?

http://techmikael.blogspot.com/2009/12/filling-array-with-default-value.html

只是为了扩大我的答案一个更好的方法做这个多次可能会是:

 PopulateByteArray(UserCode, 0x20); 

其中呼吁:

 public static void PopulateByteArray(byte[] byteArray, byte value) { for (int i = 0; i < byteArray.Length; i++) { byteArray[i] = value; } } 

这有一个很好的高效循环的优点(提及gwiazdorrr的答案),以及一个很好的整洁的外观调用,如果它被用了很多。 一眼就能看出,我个人认为是可读的。 🙂

您可以使用Parallel类(.NET 4和更新版本)来加速初始化并简化代码:

 public static void PopulateByteArray(byte[] byteArray, byte value) { Parallel.For(0, byteArray.Length, i => byteArray[i] = value); } 

当然你可以同时创build这个数组:

 public static byte[] CreateSpecialByteArray(int length, byte value) { var byteArray = new byte[length]; Parallel.For(0, length, i => byteArray[i] = value); return byteArray; } 

您可以使用集合初始值设定项 :

 UserCode = new byte[]{0x20,0x20,0x20,0x20,0x20,0x20}; 

如果值不相同,这将比Repeat更好。

这个函数比填充数组的for循环快得多。

Array.Copy命令是一个非常快速的内存复制function。 这个函数通过重复调用Array.Copy命令并且使我们复制的大小加倍,直到数组满了为止。

我在http://coding.grax.com/2013/06/fast-array-fill-function-revisited.html上的博客上讨论这个问题;

请注意,通过在方法声明中添加单词“this”就可以很容易地将其变成扩展方法,例如public static void ArrayFill<T>(this T[] arrayToFill ...

 public static void ArrayFill<T>(T[] arrayToFill, T fillValue) { // if called with a single value, wrap the value in an array and call the main function ArrayFill(arrayToFill, new T[] { fillValue }); } public static void ArrayFill<T>(T[] arrayToFill, T[] fillValue) { if (fillValue.Length >= arrayToFill.Length) { throw new ArgumentException("fillValue array length must be smaller than length of arrayToFill"); } // set the initial array value Array.Copy(fillValue, arrayToFill, fillValue.Length); int arrayToFillHalfLength = arrayToFill.Length / 2; for (int i = fillValue.Length; i < arrayToFill.Length; i *= 2) { int copyLength = i; if (i > arrayToFillHalfLength) { copyLength = arrayToFill.Length - i; } Array.Copy(arrayToFill, 0, arrayToFill, i, copyLength); } } 

这是来自post标记为答案的代码的更快版本。

我所做的所有基准testing都显示,只包含类似于数组填充的简单for循环如果递减,而不是递增, 那么通常会快两倍

此外,数组Length属性已经作为parameter passing,因此不需要从数组属性中检索。 它也应该被预先计算并分配给一个局部variables。 涉及属性访问器的循环边界计算将在循环的每次迭代之前重新计算边界的值。

 public static byte[] CreateSpecialByteArray(int length) { byte[] array = new byte[length]; int len = length - 1; for (int i = len; i >= 0; i--) { array[i] = 0x20; } return array; } 

最快的方法是使用api:

bR = 0xFF;

RtlFillMemory(pBuffer,nFileLen,bR);

使用指向缓冲区的指针,要写入的长度和编码的字节。 我认为在托pipe代码中执行它的最快方法是(更慢),即创build一个初始化字节的小块,然后使用Buffer.Blockcopy将它们写入到循环中的字节数组中。 我把它扔在一起,但没有testing,但你有这样的想法:

 long size = GetFileSize(FileName); // zero byte const int blocksize = 1024; // 1's array byte[] ntemp = new byte[blocksize]; byte[] nbyte = new byte[size]; // init 1's array for (int i = 0; i < blocksize; i++) ntemp[i] = 0xff; // get dimensions int blocks = (int)(size / blocksize); int remainder = (int)(size - (blocks * blocksize)); int count = 0; // copy to the buffer do { Buffer.BlockCopy(ntemp, 0, nbyte, blocksize * count, blocksize); count++; } while (count < blocks); // copy remaining bytes Buffer.BlockCopy(ntemp, 0, nbyte, blocksize * count, remainder);