Альтернативы BinaryFormatter
A BinaryFormatter-сериализованный массив из 128³ удваивает, занимает 50 МБ пространства. Сериализация массива из 1283 структур с двумя двойными полями занимает 150 МБ и более 20 секунд для обработки.
Существуют ли быстрые простые альтернативы, которые будут генерировать компактные файлы? Мое предположение заключается в том, что приведенные выше примеры занимают соответственно 16 и 32 Мбайт, а для обработки - менее двух секунд. Я взглянул на protobuf-net, но кажется, что он даже не поддерживает массивы struct.
PS: Я прошу прощения за ошибку при записи файлов. Фактические пробелы в пространстве с BinaryFormatter невелики.
Ответы
Ответ 1
Если вы используете BinaryWriter вместо Serializer, вы получите желаемый (mimimal) размер.
Я не уверен в скорости, но дайте ему попробовать.
В моей системе запись 32 МБ занимает менее 0,5 секунды, включая Open и Close потока.
Для записи данных вам нужно написать свои собственные контуры для, например:
struct Pair
{
public double X, Y;
}
static void WritePairs(string filename, Pair[] data)
{
using (var fs = System.IO.File.Create(filename))
using (var bw = new System.IO.BinaryWriter(fs))
{
for (int i = 0; i < data.Length; i++)
{
bw.Write(data[i].X);
bw.Write(data[i].Y);
}
}
}
static void ReadPairs(string fileName, Pair[] data)
{
using (var fs = System.IO.File.OpenRead(fileName))
using (var br = new System.IO.BinaryReader(fs))
{
for (int i = 0; i < data.Length; i++)
{
data[i].X = br.ReadDouble();
data[i].Y = br.ReadDouble();
}
}
}
Ответ 2
Сериализация означает, что метаданные добавляются таким образом, что данные могут быть безопасно десериализованы, что приводит к накладным расходам. Если вы сами сериализуете данные без каких-либо метаданных, вы получите 16 МБ данных:
foreach (double d in array) {
byte[] bin = BitConverter.GetBytes(d);
stream.Write(bin, 0, bin.Length);
}
Это, конечно, означает, что вы также должны десериализовать данные:
using (BinaryReader reader = new BinaryReader(stream)) {
for (int i = 0; i < array.Length; i++) {
byte[] data = reader.ReadBytes(8);
array[i] = BitConverter.ToDouble(data, 0);
}
}
Ответ 3
Это скорее комментарий, но это слишком много для одного... Я не могу воспроизвести ваши результаты. Тем не менее, есть несколько дополнительных накладных расходов со структурой.
Мое тестирование:
-------------------------------------------------------------------------------
Testing array of structs
Size of double: 8
Size of doubles.bin: 16777244
Size per array item: 8
Milliseconds to serialize: 143
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
Testing array of structs
Size of dd struct: 16
Size of structs.bin: 52428991
Size per array item: 25
Milliseconds to serialize: 9678
-------------------------------------------------------------------------------
код:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Diagnostics;
namespace ConsoleApplication5
{
class Program
{
static void Main(string[] args)
{
TestDoubleArray();
TestStructArray();
}
private static void TestStructArray()
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
dd[] d1 = new dd[2097152];
BinaryFormatter f1 = new BinaryFormatter();
f1.Serialize(File.Create("structs.bin"), d1);
stopWatch.Stop();
Debug.WriteLine("-------------------------------------------------------------------------------");
Debug.WriteLine("Testing array of structs");
Debug.WriteLine("");
Debug.WriteLine("Size of dd struct: " + System.Runtime.InteropServices.Marshal.SizeOf(typeof(dd)).ToString());
FileInfo fi = new FileInfo("structs.bin");
Debug.WriteLine("Size of structs.bin: " + fi.Length.ToString());
Debug.WriteLine("Size per array item: " + (fi.Length / 2097152).ToString());
Debug.WriteLine("Milliseconds to serialize: " + stopWatch.ElapsedMilliseconds);
Debug.WriteLine("-------------------------------------------------------------------------------");
}
static void TestDoubleArray()
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
double[] d = new double[2097152];
BinaryFormatter f = new BinaryFormatter();
f.Serialize(File.Create("doubles.bin"), d);
stopWatch.Stop();
Debug.WriteLine("-------------------------------------------------------------------------------");
Debug.WriteLine("Testing array of structs");
Debug.WriteLine("");
Debug.WriteLine("Size of double: " + sizeof(double).ToString());
FileInfo fi = new FileInfo("test.bin");
Debug.WriteLine("Size of doubles.bin: " + fi.Length.ToString());
Debug.WriteLine("Size per array item: " + (fi.Length / 2097152).ToString());
Debug.WriteLine("Milliseconds to serialize: " + stopWatch.ElapsedMilliseconds);
Debug.WriteLine("-------------------------------------------------------------------------------");
}
[Serializable]
struct dd
{
double a;
double b;
}
}
}