Самый быстрый способ - вручную сериализовать данные.
Простой способ сделать это - создать FileStream, а затем обернуть его в BinaryWriter / BinaryReader.
У вас есть доступ к функциям для записи основных структур данных (numbers
, string
, char
, byte[]
и char[]
).
Простой способ записать int[]
(ненужный, если он имеет фиксированный размер), добавив длину массива либо к int / long (в зависимости от размера, unsigned на самом деле не дает никаких преимуществ, поскольку массивы использовать подписанные типы данных для хранения их длины). А затем напишите все целые.
Два способа записать все целые будут следующими:
1. Просто зациклите весь массив.
2. Преобразуйте его в byte[]
и запишите, используя BinaryWriter.Write(byte[])
Вот как вы можете реализовать их оба:
// Writing
BinaryWriter writer = new BinaryWriter(new FileStream(...));
int[] intArr = new int[1000];
writer.Write(intArr.Length);
for (int i = 0; i < intArr.Length; i++)
writer.Write(intArr[i]);
// Reading
BinaryReader reader = new BinaryReader(new FileStream(...));
int[] intArr = new int[reader.ReadInt32()];
for (int i = 0; i < intArr.Length; i++)
intArr[i] = reader.ReadInt32();
// Writing, method 2
BinaryWriter writer = new BinaryWriter(new FileStream(...));
int[] intArr = new int[1000];
byte[] byteArr = new byte[intArr.Length * sizeof(int)];
Buffer.BlockCopy(intArr, 0, byteArr, 0, intArr.Length * sizeof(int));
writer.Write(intArr.Length);
writer.Write(byteArr);
// Reading, method 2
BinaryReader reader = new BinaryReader(new FileStream(...));
int[] intArr = new int[reader.ReadInt32()];
byte[] byteArr = reader.ReadBytes(intArr.Length * sizeof(int));
Buffer.BlockCopy(byteArr, 0, intArr, 0, byteArr.Length);
Я решил проверить все это на массиве из 10000 целых чисел, и я провел тест 10000 раз.
В результате первый метод потребляет в моей системе в среднем 888200 нс (около 0,89 мс).
В то время как метод 2 потребляет в моей системе всего 568600 нс (в среднем 0,57 мс).
Оба раза включают работу, которую должен выполнять сборщик мусора.
Очевидно, что метод 2 быстрее, чем метод 1, хотя, возможно, менее читабелен.
Еще одна причина, по которой метод 1 может быть лучше метода 2, заключается в том, что для метода 2 требуется вдвое больше свободной оперативной памяти, чем для данных, которые вы собираетесь записать (оригинал int[]
и byte[]
, преобразованные из * 1035). *), когда речь идет об ограниченном объеме ОЗУ / очень больших файлах (речь идет о 512 МБ +), хотя в этом случае вы всегда можете сделать гибридное решение, например, записав 128 МБ за раз.
Обратите внимание, что метод 1 также требует этого дополнительного пространства, но поскольку он разделен на 1 операцию на элемент int[]
, он может освободить память намного раньше.
Как-то так, будет записывать 128 МБ int[]
одновременно:
const int WRITECOUNT = 32 * 1024 * 1024; // 32 * sizeof(int)MB
int[] intArr = new int[140 * 1024 * 1024]; // 140 * sizeof(int)MB
for (int i = 0; i < intArr.Length; i++)
intArr[i] = i;
byte[] byteArr = new byte[WRITECOUNT * sizeof(int)]; // 128MB
int dataDone = 0;
using (Stream fileStream = new FileStream("data.dat", FileMode.Create))
using (BinaryWriter writer = new BinaryWriter(fileStream))
{
while (dataDone < intArr.Length)
{
int dataToWrite = intArr.Length - dataDone;
if (dataToWrite > WRITECOUNT) dataToWrite = WRITECOUNT;
Buffer.BlockCopy(intArr, dataDone, byteArr, 0, dataToWrite * sizeof(int));
writer.Write(byteArr);
dataDone += dataToWrite;
}
}
Обратите внимание, что это только для письма, чтение работает по-другому тоже:
Я надеюсь, что это даст вам более глубокое понимание работы с очень большими файлами данных:).