Сохранение текущего состояния объектов в файлах
1. Цель работы. Получение навыков в разработке программ с использованием файлов, сохранения информации в них и работы с ними.
2. Общие сведения
При разработке приложений часто возникают две в общем случае схожие задачи: сохранить (прочитать) содержимое данных (файла) и сохранить (прочитать) текущее состояние объекта в файле или таблице базы данных. Несмотря на несомненную схожесть указанных задач, для решения каждой из них предусмотрены свои классы.
Техника работы с файлами зависит от типа файла (текстовый или двоичный). При работе с текстовыми файлами сначала создается поток класса FileStream. Данные записываются в файл с помощью вспомогательного объекта класса StreamWriter, а читаются объектом класса StreamReader. При создании объекта FileStream ему передаются имя файла и два параметра: FileMode, определяющий способ создания потока, и FileAccess, регулирующий доступ потока к данным.
Таблица1.
Значение параметра FileMode
Значение | Описание |
Append | Добавляет записи в существующий файл или создает новый. Требует, чтобы параметр FileMode имел значение Write |
Create | Создает новый файл или переписывает существующий. Требует, чтобы параметр FileMode имел значение Write |
CreateNew | Создает новый файл, а если он уже существует, возникает исключение. Требует, чтобы параметр FileMode имел значение Write |
Open | Открывает существующий файл. Если файла нет, возникает исключение |
OpenOrCreate | Открывает существующий или создает новый файл, если он еще не создан |
Truncate | Открывает существующий файл и делает его размер равным нулю |
Таблица2.
Значение параметра FileAccess
Значение | Описание |
Read | Поток может читать данные |
ReadWrite | Поток может читать и записывать данные |
Write | Поток может записывать данные |
Для потока существует понятие текущей записи — в эту запись помещаются данные и из нее они считываются. Положением текущей записи можно управлять с помощью метода Seek(), имеющего такую сигнатуру:
public virtual long Seek (int Offset, SeekOrigin Origin);
Здесь Offset — смещение относительно позиции, указанной параметром Origin.
Таблица3.
Значение параметра SeekOrigin
Значение | Описание |
Begin | Соответствует началу потока |
Current | Соответствует текущей записи потока |
End | Соответствует концу потока |
Физическая запись данных в файл реализуется в момент закрытия потока методом Close() или выталкиванием записей из промежуточного буфера методом Flush(). Во втором случае поток не закрывается и готов к продолжению операций.
Обработка двоичных файлов во многом подобна обработке текстовых: сначала создается поток, затем — объекты BinaryWriter или BinaryReader в зависимости от направления передачи данных (в файл или из файла).
C# поддерживает интересную технологию сохранения текущего состояния объекта на некотором носителе информации. Эта технология называется сериализацией объекта. Сериализованный объект может быть, например, передан по сети на другой компьютер и там восстановлен в первоначальном состоянии — этот процесс называется десериализацией.
Особенностью сериализации является то, что ее можно применять к классам, поддерживающим эту процедуру. Для этого класс должен объявляться с атрибутом [Serializable] или в его объявлении должно быть явное указание на то, что он исполняет интерфейс ISerializable. Лишь относительно небольшое количество (менее 40) стандартных классов реализуют данный интерфейс. Это, в основном, классы, используемые как хранилища данных.
Следующий пример иллюстрирует данную технологию.
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace Project5
{
[Serializable]
class queue
{
private int q=50;
private char[] arrchar= new char[4] {'a','b','c','d'};
public int p;
public char ch;
}
[Serializable]
class queue1 : queue
{
private int r = 50;
public new int q=50;
public new char[] arrchar= new char[4] {'e','f','g','h'};
public queue1() {}
public queue1(int q, int i)
{ p = q*r;
ch = arrchar[i];
}
}
class Executer
{
[STAThread]
static void Main()
{
queue1 a = new queue1();
queue1 b = new queue1(50,2);
queue1 c = new queue1(500,1);
FileStream fs;
fs = new FileStream
("File_queue.bin",FileMode.Create,FileAccess.Write);
BinaryFormatter sw = new BinaryFormatter();
sw.Serialize(fs,b);
sw.Serialize(fs,c);
fs.Close();
fs = new FileStream
("File_queue.bin",FileMode.Open,FileAccess.Read);
long i=0,
j = fs.Length/231; //231 — количество байт занимаемых одним объектом класса queue1
while (i < j)
{
a = (queue1) sw.Deserialize(fs);
Console.WriteLine(a.p);
Console.WriteLine(a.ch);
i++;
}
fs.Close();
Console.ReadLine();
}
}
}
Постановка задачи
Создать объекты класса <имя класса> (класс и его поля задаются в соответствии с выбранным вариантом в лабораторной работе 1), причем объекты класса должны хранить данных о предметной области, связанные со свойствами предмета задания по варианту. Сохранить данные объекты в файле. Причем сохранить необходимо как отдельные объекты, так объект контейнерного типа, полученный в лабораторной работе 4. Считать сохраненные данные из файла и вывести их на экран.