Есть список объектов, который нужно сохранить в файл. Могу сохранять в файлы трех типов: текстовые, бинарные и xml. Нужен метод, который будет определять размер файлов, содержащих мой список объектов. Т.е. у меня есть список объектов, который я хочу сохранить в файл, я вызываю этот метод, а он мне сообщает: сколько памяти потребуется для текстового файла, сколько для бинарного и сколько для xml-файла. Поля моего класса:
[Serializable]
public class Equipment
{
public string Department { get; set; }
public string Name { get; set; }
int amount;
double unitCost;
double totalCost;
}
Методы для записи файлов:
public static void WriteTxtFile(List<Equipment> equipments, string path)
{
using (StreamWriter writer = new StreamWriter(path, false))
{
equipments.ForEach(equipment => writer.WriteLine($"{equipment.Department};{equipment.Name};{equipment.Amount};{equipment.UnitCost};{equipment.TotalCost}"));
}
}
public static void WriteBinaryFile(List<Equipment> equipments, string path)
{
using (BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.OpenOrCreate)))
{
foreach(Equipment equipment in equipments)
{
writer.Write(equipment.Department);
writer.Write(equipment.Name);
writer.Write(equipment.Amount);
writer.Write(equipment.UnitCost);
writer.Write(equipment.TotalCost);
}
}
}
public static void WriteXmlFile(List<Equipment> equipments, string path)
{
XmlSerializer formatter = new XmlSerializer(typeof(List<Equipment>));
using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate))
{
formatter.Serialize(fs, equipments);
}
}
Создайте свой класс, производный от Stream, который вместо записи данных будет считать их размер:
public class MyStream : Stream
{
int c = 0;
public override bool CanRead => false;
public override bool CanSeek => false;
public override bool CanWrite => true;
public override long Length => с;
public override long Position { get => c; set => throw new NotSupportedException(); }
public override void Flush()
{
return;
}
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
c += count;
}
}
Создайте для каждого метода перегрузку, которая будет писать те же данные, но не в файл, а в Stream:
public static void WriteTxtFile(List<Equipment> equipments, Stream s)
{
StreamWriter writer = new StreamWriter(s);
equipments.ForEach(equipment => writer.WriteLine($"{equipment.Department};{equipment.Name};{equipment.Amount};{equipment.UnitCost};{equipment.TotalCost}"));
writer.Flush();
}
Тогда размер данных вы сможете определить так:
MyStream s = new MyStream();
WriteTxtFile(eqlist, s);
Console.WriteLine("Text file size: " + s.Position);
есть список объектов, который я хочу сохранить в файл
сколько памяти потребуется для текстового файла, сколько для бинарного и сколько для xml-файла
Допустим, имеется следующий класс:
public class Equipment
{
//public string Department { get; set; }
//public string Name { get; set; }
public int amount { get; set; }
public double unitCost { get; set; }
public double totalCost { get; set; }
}
И записывается он в бинарный файл с помощью BinaryWriter:
binaryWriter.Write(equipment.amount);
binaryWriter.Write(equipment.unitCost);
binaryWriter.Write(equipment.totalCost);
То есть данные идут вплотную, без дополнительной метаинформации.
Размер примитивных типов можно получить оператором sizeof. Следовательно, размер одного экземпляра и всего списка вычисляется следующим образом:
int equipmentSize = sizeof(int) + sizeof(double) + sizeof(double);
int listSize = equipmentSize * equipmentList.Count;
O(1) - эффективнее некуда.
Однако, если раскомментировать строковые свойства, то ситуация усложнится.
Длина строки в байтах зависит от используемой кодировки (BinaryWriter
может использовать любую). Следовательно, нужно вычислять эту длину.
int nameSize = encoding.GetByteCount(equipment.Name);
int departmentSize = encoding.GetByteCount(equipment.Department);
где encoding
- та же кодировка, что используется при записи в файл.
Естественно, длина строк у разных объектов в списке может быть разная, поэтому придётся сделать проход по всему списку и добавить сумму длин в listSize
. Получаем O(n).
Дело осложняется тем, что при записи строк в файл BinaryWriter
предваряет значение записываемой строки её длиной. Это значение тоже нужно приплюсовать к итоговому размеру. Причём длина рассчитывается как 7-bit encoded. Подробнее здесь и здесь.
Вычисление размера текстового файла зависит от используемой кодировки и от формата. Его сделать относительно несложно используя метод Encoding.GetByteCount
.
XML-файл по сути является текстовым. Аналогично, его размер можно рассчитать аналитически, без самой записи. Но возникает много проблем с предварительным определением его формата: с индентацией и без, с переносом атрибутов на новую строку или без переноса и многое другое.
При желании, можно заморочиться ручным вычислением. Но это окупится лишь в том случае, если нужно рассчитывать размеры большого количества файлов/потоков большого размера. А главное, код в ответе MSDN.WhiteKnight именно это и делает.
Оборудование для ресторана: новинки профессиональной кухонной техники
Частный дом престарелых в Киеве: комфорт, забота и профессиональный уход
как реализовать в xnet SSLv3-compatible ClientHello запрос
Вот код, на другой машине все работало, сервер давал ответ, сейчас пишет