Понимание сохранения: я использую только Stream или использую и Formatter, и Stream?

Насколько я понимаю, Formatter преобразует сериализуемый объект в поток байтов, а Stream (например, FileStream) выполняет фактическую запись этих байтов в файл. Пример кода:

public static void SaveData(MySerializableData data)
{
    BinaryFormatter formatter = new BinaryFormatter();
    FileStream stream = new FileStream(SavePath, FileMode.Create);        
    formatter.Serialize(stream, data);
    stream.Close();
}

Однако в другое время я также вижу этот тип кода:

void Save()
{
    string data = "Value 1";
    StreamWriter writer = new StreamWriter("MySaveFile.txt", true);
    writer.Write(data);
}

Почему во втором случае мы отказываемся от двухэтапного процесса сохранения? Почему иногда мы используем только StreamWriter, а иногда используем и средство форматирования, и объект потока?

Спасибо!


person Komm    schedule 15.10.2020    source источник


Ответы (1)


BinaryFormatter сериализует класс в массив байтов и записывает его в поток. Это полезно, когда вы хотите сохранить/загрузить классы с его данными. Serializtion хранит метаданные о сохраняемом графе классов.

StreamWriter — это поток, который имеет специальные функции для записи строки в файл.

Рассмотрим этот пример:

MemoryStream mstr = new MemoryStream();

string datastr = "hello!";

BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(mstr, datastr);
mstr.Seek(0, SeekOrigin.Begin);

string resultString = Encoding.ASCII.GetString(mstr.ToArray());

Если вы проверите resultString, вы обнаружите, что он содержит что-то вроде этого:

"\0\u0001\0\0\0????\u0001\0\0\0\0\0\0\0\u0006\u0001\0\0\0\u0006hello!\v"

Ну, это не то, что вы хотели бы иметь в текстовом файле, верно? Как видите, сериализация предназначена не для хранения необработанных данных, а для хранения экземпляров классов.

Теперь проверьте это:

MemoryStream mstr = new MemoryStream();
StreamWriter sw = new StreamWriter(mstr);
string datastr = "hello!";
sw.Write(datastr);
mstr.Seek(0, SeekOrigin.Begin);
sw.Close();

string resultString = Encoding.ASCII.GetString(mstr.ToArray());

Если вы сейчас проверите resultString, он будет содержать:

"hello!"

Как вы видите, это совсем другое, это то, что вы ожидаете в текстовом файле.

Вы также можете хранить необработанные двоичные данные с потоком:

byte[] data = new byte[]{ 1,2,3,4 };
var fs = File.Create("out.dat"); //this creates a new file and creates a filestream
fs.Write(data, 0, data.Length);
fs.Close();

Если вы теперь просмотрите файл с помощью двоичного редактора, вы увидите, что он содержит:

0x01, 0x02, 0x03, 0x04

Существует много типов потоков с разными целями (например, MemoryStream, который я использовал в примерах, двоичный поток, который хранит свои данные в массиве в памяти) и множество классов, которые используют потоки для многих вещей, в этом случае вы смешали концепции сериализации и хранения данных с использованием потоков, это две разные вещи.

person Gusman    schedule 15.10.2020
comment
Интересно... да, у них обоих есть метод .write(), так что я пытался сравнить их одинаково, :/ Чувак... Спасибо за отличное объяснение! - person Komm; 16.10.2020