Самый быстрый способ извлечь целое число переменной ширины со знаком из байта[]
Название говорит само за себя. У меня есть файл, содержащий кодировку base64 byte[] переменной ширины целого числа, min 8 бит, max 32 бит
У меня есть большой файл (48 МБ), и я пытаюсь найти самый быстрый способ захвата целых чисел из потока.
Это самый быстрый код из perf приложения:
static int[] Base64ToIntArray3(string base64, int size)
{
List<int> res = new List<int>();
byte[] buffer = new byte[4];
using (var ms = new System.IO.MemoryStream(Convert.FromBase64String(base64)))
{
while(ms.Position < ms.Length)
{
ms.Read(buffer, 0, size);
res.Add(BitConverter.ToInt32(buffer, 0));
}
}
return res.ToArray();
}
Я не вижу более быстрого способа заполнения байтов до 32 бит. Есть какие-нибудь идеи, ребята? Решения должны быть на языке c#. Я мог бы опуститься до C/++, если нужно, но я этого не делаю хочу.
3 ответов:
Нет никаких причин использовать поток памяти для перемещения байтов из массива в другой массив, просто считывайте данные непосредственно из массива. Кроме того, размер массива известен, поэтому необходимо добавить элементы в список, который затем преобразуется в массив, вы можете использовать массив с самого начала:
static int[] Base64ToIntArray3(string base64, int size) { byte[] data = Convert.FromBase64String(base64); int cnt = data.Length / size; int[] res = new int[cnt]; for (int i = 0; i < cnt; i++) { switch (size) { case 1: res[i] = data[i]; break; case 2: res[i] = BitConverter.ToInt16(data, i * 2); break; case 3: res[i] = data[i * 3] + data[i * 3 + 1] * 256 + data[i * 3 + 2] * 65536; break; case 4: res[i] = BitConverter.ToInt32(data, i * 4); break; } } return res; }Примечание: непроверенный код! Вы должны убедиться, что он действительно делает то, что должен делать, но, по крайней мере, он показывает принцип.
Вероятно, именно так я бы и поступил. Отказ от использования потока должен повысить производительность. Это похоже на то, что должно быть легко сделать с помощью Linq, но я не мог понять этого.
static int[] Base64ToIntArray3(string base64, int size) { if (size < 1 || size > 4) throw new ArgumentOutOfRangeException("size"); byte[] data = Convert.FromBase64String(base64); List<int> res = new List<int>(); byte[] buffer = new byte[4]; for (int i = 0; i < data.Length; i += size ) { Buffer.BlockCopy(data, i, buffer, 0, size); res.Add(BitConverter.ToInt32(buffer, 0)); } return res.ToArray(); }
Итак, я считаю, что это Linq-способ сделать это:
static int[] Base64ToIntArray3(string base64, int size) { byte[] data = Convert.FromBase64String(base64); return data.Select((Value, Index) => new { Value, Index }) .GroupBy(p => p.Index / size) .Select(g => BitConverter.ToInt32(g.Select(p => p.Value).Union(new byte[4 - size]).ToArray(), 0)) .ToArray(); }
Comments