Инициализировать массив байтов до определенного значения, отличного от значения по умолчанию null? [дубликат]
этот вопрос уже есть ответ здесь:
Что такое эквивалент memset в C#?
13 ответов
Я занят переписыванием старого проекта, который был сделан в C++, на C#.
моя задача-переписать программу так, чтобы она функционировала как можно ближе к оригиналу.
во время куча обработки файлов предыдущий разработчик, написавший эту программу, создает структуру, содержащую тонну полей, соответствующих заданному формату, в который должен быть записан файл, поэтому вся эта работа уже выполнена для меня.
все эти поля являются байтовыми массивами. То, что код 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] в конструкторе массив байтов автоматически инициализируется до значений null по умолчанию. Неужели это невозможно? что я могу сделать его все пробелы после объявления, так что когда я вызываю конструктор моего класса, что он инициализируется сразу, как это? Или какой-нибудь memsetподобная функция?
13 ответов:
для небольших массивов используйте синтаксис инициализации массива:
var sevenItems = new byte[] { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };для больших массивов используйте стандартный
forпетли. Это самый читаемый и эффективный способ сделать это:var sevenThousandItems = new byte[7000]; for (int i = 0; i < sevenThousandItems.Length; i++) { sevenThousandItems[i] = 0x20; }конечно, если вам нужно сделать это много, то вы можете создать вспомогательный метод, чтобы помочь сохранить ваш код кратким:
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; }
используйте это для создания массива в первую очередь:
byte[] array = Enumerable.Repeat((byte)0x20, <number of elements>).ToArray();заменить
<number of elements>с нужным размером массива.
можно использовать перечисли.Повторить ()
массив из 100 элементов, инициализированных до 0x20:
byte[] arr1 = Enumerable.Repeat(0x20,100).ToArray();
если вам нужно инициализировать небольшой массив, вы можете использовать:
byte[] smallArray = new byte[] { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };если у вас большой массив, то вы можете использовать:
byte[] bitBiggerArray Enumerable.Repeat(0x20, 7000).ToArray();что просто, и легко для следующего парня/девушки, чтобы читать. И будет достаточно быстро 99,9% времени. (Обычно это будет оптимальный вариант™)
однако, если вам действительно нужна супер скорость, вызов оптимизированного метода memset, используя P / invoke, для вас: (Здесь завернутый в приятно использовать класс)
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);
может быть, это может быть полезно?
что такое эквивалент memset в C#?
http://techmikael.blogspot.com/2009/12/filling-array-with-default-value.html
ребята передо мной дали вам свой ответ. Я просто хочу указать на ваше неправильное использование цикла foreach. Смотрите, так как вы должны увеличить индекс стандартного "for loop" будет не только более компактным, но и более эффективным ("foreach" делает много вещей под капотом):
for (int index = 0; index < UserCode.Length; ++index) { UserCode[index] = 0x20; }
самый быстрый способ сделать это-использовать API:
bR = 0xFF;
RtlFillMemory(pBuffer, nFileLen, bR);
используя указатель на буфер, длину для записи и закодированный байт. Я думаю, что самый быстрый способ сделать это в управляемом коде (гораздо медленнее) - создать небольшой блок инициализированных байтов, а затем использовать буфер.Blockcopy для записи их в массив байтов в цикле. Я бросил это вместе, но не проверял его, но вы получите идею:
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);
просто чтобы расширить мой ответ, более аккуратный способ сделать это несколько раз, вероятно, будет:
PopulateByteArray(UserCode, 0x20);которых вызовы:
public static void PopulateByteArray(byte[] byteArray, byte value) { for (int i = 0; i < byteArray.Length; i++) { byteArray[i] = value; } }это имеет преимущество хорошего эффективного цикла for (упоминание ответа gwiazdorrr), а также приятный аккуратный вызов, если он используется много. И много mroe на первый взгляд читается, чем перечисление один я лично думаю. :)
можно использовать коллекции инициализатор:
UserCode = new byte[]{0x20,0x20,0x20,0x20,0x20,0x20};это будет работать лучше, чем
Repeatесли значения не совпадают.
эта функция намного быстрее, чем цикл для заполнения массива.
Массив.Команда копирования-это очень быстрая функция копирования памяти. Эта функция использует это, повторно вызывая массив.Скопируйте команду и удвоение размера того, что мы копируем, пока массив не будет заполнен.
Я обсуждаю это в своем блоге на http://coding.grax.com/2013/06/fast-array-fill-function-revisited.html
обратите внимание, что это будет легко сделать в метод расширения, просто добавив слово " это " в объявления метода, т. е.
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); } }
это более быстрая версия кода из сообщения, помеченного как ответ.
все тесты, которые я выполнил, показывают, что простой цикл который содержит только что-то вроде заполнения массива обычно в два раза быстрее, если он уменьшается против, если он увеличивается.
кроме того, свойство длины массива уже передается в качестве параметра, поэтому его не нужно извлекать из свойств массива. Следует также предварительно вычисляется и присваивается локальной переменной. Вычисления границ цикла, которые включают a свойства-аксессоры будет повторно вычислять значение границ перед каждой итерацией цикла.
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; }
вы можете ускорить инициализацию и упростить код с помощью параллельного класса (.NET 4 и новее):
public static void PopulateByteArray(byte[] byteArray, byte value) { Parallel.For(0, byteArray.Length, i => byteArray[i] = value); }конечно, вы можете создать массив одновременно:
public static byte[] CreateSpecialByteArray(int length, byte value) { var byteArray = new byte[length]; Parallel.For(0, length, i => byteArray[i] = value); return byteArray; }
Comments