Ответ 1
Самый быстрый способ состоит в ручной сериализации данных.
Легкий способ сделать это - создать FileStream, а затем обернуть его в BinaryWriter/BinaryReader.
У вас есть доступ к функциям для записи базовых структур данных (numbers
, string
, char
, byte[]
и char[]
).
Легкий способ записи int[]
(ненужный, если фиксированный размер) заключается в добавлении длины массива с использованием int/long (в зависимости от размера unsigned не дает никаких преимуществ, поскольку массивы использовать подписанные типы данных для хранения их длины). А затем напишите все ints.
Два способа записать все ints:
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 раз.
Это привело к тому, что один метод потребляет в моей системе в среднем 888200ns (около 0,89 мс).
Хотя метод 2 потребляет в среднем только 568600ns в моей системе (0,57 мс в среднем).
Оба раза включают работу, которую должен сделать сборщик мусора.
Очевидно, что метод 2 быстрее, чем метод 1, хотя, возможно, менее читаемый.
Другая причина, по которой метод 1 может быть лучше, чем метод 2, заключается в том, что для метода 2 требуется вдвое больше объема оперативной памяти, чем данные, которые вы собираетесь писать (исходные int[]
и byte[]
, которые были преобразованы из int[]
) при работе с ограниченным ОЗУ/чрезвычайно большими файлами (речь идет о 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;
}
}
Обратите внимание, что это только для записи, чтение работает по-разному: P. Надеюсь, это даст вам более глубокое представление о работе с очень большими файлами данных:).