513.41K
Category: programmingprogramming

Сериализация. Лекция 37

1.

Лекция 37
Сериализация
1

2.

Сериализация
Сериализация представляет процесс
преобразования какого-либо объекта в
поток байтов. После преобразования
можно этот поток байтов или записать на
диск или сохранить его временно в
памяти. А при необходимости можно
выполнить обратный процесс десериализацию, то есть получить из
потока байтов ранее сохраненный объект.
2

3.

Пример 1
[Serializable]
class Person{
public string Name { get; set; }
public int Year { get; set; }
[NonSerialized]
public string accNumber;
public Person(string name, int year, string acc) {
Name = name;
Year = year;
accNumber = acc;
}
}
[Serializable]
class Worker : Person ...
3

4.

Сериализация
В .NET можно использовать следующие
форматы: бинарный, SOAP, xml, JSON.
Для каждого формата предусмотрен свой класс:
для сериализации в бинарный формат класс BinaryFormatter (способен сериализовать
объекты в двоичные данные и обратно),
для формата SOAP - класс SoapFormatter
(способен сериализовать объекты в SOAP-формат
XML-данных и наоборот),
для xml - XmlSerializer,
для json - DataContractJsonSerializer.
4

5.

Сериализация
Классы BinaryFormatter и SoapFormatter
реализуют интерфейс IFormatter.
Методы интерфейса IFormatter:
void Serialize (Stream stream, object source) Сериализует объект source в ПОТОК
stream
object Deserialize (Stream stream) Десериализует данные в stream и
возвращает результирующий объект
5

6.

Пример 2
using System; // Бинарная сериализация. BinaryFormatter
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace Serialization{
[Serializable]
class Person {
public string Name { get; set; }
public int Age { get; set; }
public Person(string name, int age) {
Name = name;
Age = age;
}
}
6

7.

Пример 2
class Program {
static void Main(string[] args) {
// объект для сериализации
Person person = new Person("Tom", 29);
Console.WriteLine("Объект создан");
// создание объекта BinaryFormatter
BinaryFormatter formatter = new BinaryFormatter();
// получить поток, куда будет
// записываться сериализованный объект
using (FileStream fs = new FileStream("people.dat",
FileMode.OpenOrCreate)) {
formatter.Serialize(fs, person);
Console.WriteLine("Объект сериализован"); 7
}

8.

Пример 2
// десериализация из файла people.dat
using (FileStream fs = new FileStream("people.dat",
FileMode.OpenOrCreate)) {
Person newPerson = (Person)formatter.Deserialize(fs);
Console.WriteLine("Объект десериализован");
Console.WriteLine("Имя: {0} --- Возраст: {1}",
newPerson.Name, newPerson.Age);
}
Console.ReadLine();
}
}
}
8

9.

Пример 3
namespace Serialization{ // Сериализация массива объектов
[Serializable]
class Person {
public string Name { get; set; }
public int Age { get; set; }
public Person(string name, int age) {
Name = name;
Age = age;
}
}
9

10.

Пример 3
class Program {
static void Main(string[] args) {
Person person1 = new Person("Tom", 29);
Person person2 = new Person("Bill", 25);
// массив для сериализации
Person[] people = new Person[] { person1, person2 };
BinaryFormatter formatter = new BinaryFormatter();
using (FileStream fs = new FileStream("people.dat",
FileMode.OpenOrCreate)){
// сериализация всего массива people
formatter.Serialize(fs, people);
Console.WriteLine("Объект сериализован");
}
10

11.

Пример 3
// десериализация
using (FileStream fs = new FileStream("people.dat",
FileMode.OpenOrCreate)){
Person[] deserilizePeople =
(Person[])formatter.Deserialize(fs);
foreach (Person p in deserilizePeople) {
Console.WriteLine("Имя: {0} --- Возраст: {1}",
p.Name, p.Age);
}
}
Console.ReadLine();
}
}
11
}

12.

Пример 4 (ООП)
12

13.

Пример 4 (ООП)
using System;

using System.IO;
using System.Runtime.Serialization; //для сериализации
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms;
namespace WindowsFormsApp101{
public partial class Form1 : Form {
string ss;
// объявление глобальных переменных
static int dgod = 0, dmes = 0, ddan = 0, dh = 0, dmin = 0, dsek = 0;
DateTime date; // дата и время события
Fo sob = new Fo (); // объект класса
List<Fo> mySob = new List<Fo>(); // коллекция объектов класса
13

14.

Пример 4 (ООП)
private void button2_Click(object sender, EventArgs e) { // Сохранить
sob.S_N = textBox3.Text; // название события
sob.S_D = maskedTextBox1.Text; // дата (маска ввода dd.mm.yyyy)
sob.S_T = maskedTextBox2.Text; // время (маска ввода hh:mm)
// сериализация
mySob.Add(new Fo(sob)); // добавление объекта в коллекцию
// получить сериализатор
IFormatter serializer = new BinaryFormatter();
// сериализовать события - записать коллекцию в файл
FileStream saveFile = new FileStream("Pros.bin",
FileMode.Create, FileAccess.Write);
serializer.Serialize(saveFile, mySob);
saveFile.Close(); // сохранить данные
listBox1.Items.Clear();
mySob.Clear();
14

15.

Пример 4 (ООП)
// десериализовать события - считать данные
// из файла в коллекцию
FileStream loadFile = new FileStream("Pros.bin",
FileMode.Open, FileAccess.Read);
mySob = serializer.Deserialize(loadFile) as List<Fo>;
loadFile.Close();
int n = 0;
foreach (Fo Sob in mySob) { // сформировать список
listBox1.Items.Add(mySob[n].S_N + " " + mySob[n].S_D + "
" + mySob[n].S_T);
n++;
}
}
15

16.

Пример 4 (ООП)
private void button3_Click(object sender, EventArgs e){ // Отсчет
timer1.Stop(); // выключить таймер
// индекс выбранной записи в списке
int z = listBox1.SelectedIndex;
if (z > -1) {
ss = mySob[z].S_N; // название события из коллекции
// дата из коллекции (dd.mm.yyyy)
string s1 = mySob[z].S_D;
// выделение из даты дня в переменную ddan
int k = s1.IndexOf('.');
string snam = s1.Substring(0, k).Trim();
s1 = s1.Remove(0, k+1).Trim();
if (snam[0] == '0') snam = snam.Remove(0, 1).Trim();
ddan = Convert.ToInt32(snam.Trim());
16

17.

Пример 4 (ООП)
// выделение из даты месяца в переменную dmes
k = s1.IndexOf('.');
snam = s1.Substring(0, k).Trim();
s1 = s1.Remove(0, k+1).Trim();
if (snam[0] == '0') snam = snam.Remove(0, 1).Trim();
dmes = Convert.ToInt32(snam.Trim());
// выделение из даты года в переменную dgod
snam = s1.Trim();
if (snam[0] == '0') snam = snam.Remove(0, 1).Trim();
dgod = Convert.ToInt32(snam.Trim());
// время из коллекции (маска ввода hh:mm)
s1 = mySob[z].S_T;
// выделение из времени часов в переменную dh
k = s1.IndexOf(':');
snam = s1.Substring(0, k).Trim();
s1 = s1.Remove(0, k+1).Trim();
17

18.

Пример 4 (ООП)
if (snam[0] == '0') snam = snam.Remove(0, 1).Trim();
dh = Convert.ToInt32(snam.Trim());
// выделение из времени минут в переменную dmin
snam = s1.Trim();
if (snam[0] == '0') snam = snam.Remove(0, 1).Trim();
dmin = Convert.ToInt32(snam.Trim());
dsek = 0; // секунды
// создание даты события
// год - месяц - день - час - минута – секунда
date = new DateTime(dgod, dmes, ddan, dh, dmin, dsek);
// вызов события через определенный интервал
timer1.Tick += timer1_Tick;
timer1.Start(); // включить таймер
}
}
18

19.

Пример 4 (ООП)
public Form1() { // конструктор формы
InitializeComponent();
IFormatter serializer = new BinaryFormatter(); // сериализатор
FileStream loadFile = new FileStream("Products.bin",
FileMode.Open, FileAccess.Read);
if (loadFile.Length != 0) { // если есть данные в файле - считать
mySob = serializer.Deserialize(loadFile) as List<Fo>;
int n = 0;
foreach (Fo Sob in mySob) {
listBox1.Items.Add(mySob[n].S_N + " " + mySob[n].S_D + "
" + mySob[n].S_T);
n++;
}
}
loadFile.Close();
textBox3.Focus();
19
}

20.

Пример 4 (ООП)
private void timer1_Tick(object sender, EventArgs e) {
DateTime tt = new DateTime(); // объект дата-время
tt = System.DateTime.Now; // текущие дата и время
// разность дней от события до текущей даты
double dan = date.Subtract(tt).TotalDays;
// разность часов от события до часов текущего времени
double h = date.Subtract(tt).TotalHours;
// разность минут от события до минут текущего времени
double min = date.Subtract(tt).TotalMinutes;
int dan1 = (int)dan; // количество дней
int h1 = (int)h - (dan1*24); // количество часов
int min1 = (int)min - (int)h*60; // количество минут
toolStripStatusLabel1.Text = "Осталось " + dan1.ToString() + "
дней, " + h1.ToString() + " часов, " + min1.ToString() + " минут!
до события: " + ss;
20
}
} // end class Form1

21.

Пример 4 (ООП)
[Serializable] // сериализация
public class Fo { // пользовательский класс
string s_name; // название события
string s_date; // дата события
string s_time; // время события
public Fo() { // конструктор по умолчанию
s_name = "";
s_date = "";
s_time = "";
}
public Fo (Fo x){ // конструктор с параметрами
s_name = x.S_N;
s_date = x.S_D;
s_time = x.S_T;
}
21

22.

Пример 4 (ООП)
public string S_N { // объявление свойства
get { return s_name; } // аксессор чтения поля
set { s_name = value; } // аксессор записи в поле
}
public string S_D{ // объявление свойства
get { return s_date; } // аксессор чтения поля
set { s_date = value; } // аксессор записи в поле
}
public string S_T { // объявление свойства
get { return s_time; } // аксессор чтения поля
set { s_time = value; } // аксессор записи в поле
}
} // end class Fo
} // end namespace WindowsFormsApp101
22

23.

Сериализация в формат SOAP. SoapFormatter
Протокол SOAP (Simple Object Access
Protocol) представляет простой протокол
для обмена данными между различными
платформами. При такой сериализации
данные упакуются в конверт SOAP,
данные в котором имеют вид xmlподобного документа. Прежде чем
использовать класс SoapFormatter, надо
добавить в проект сборку
System.Runtime.Serialization.Formatters.Soap.dll.
23

24.

Пример 5
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Soap;
namespace Serialization{
[Serializable]
class Person {
public string Name { get; set; }
public int Age { get; set; }
public Person(string name, int age) {
Name = name;
Age = age;
}
}
24

25.

Пример 5
class Program {
static void Main(string[] args) {
Person person = new Person("Tom", 29);
Person person2 = new Person("Bill", 25);
Person[] people = new Person[] { person, person2 };
// создание объекта SoapFormatter
SoapFormatter formatter = new SoapFormatter();
// получение потока, куда будет
// записываться сериализованный объект
using (FileStream fs = new
FileStream("people.soap", FileMode.OpenOrCreate)) {
formatter.Serialize(fs, people);
Console.WriteLine("Объект сериализован");
25
}

26.

Пример 5
// десериализация
using (FileStream fs = new
FileStream("people.soap", FileMode.OpenOrCreate)) {
Person[] newPeople =
(Person[])formatter.Deserialize(fs);
Console.WriteLine("Объект десериализован");
foreach (Person p in newPeople) {
Console.WriteLine("Имя: {0} --- Возраст: {1}",
p.Name, p.Age);
}
}
Console.ReadLine();
}
}
26
}

27.

Сериализация в XML. XmlSerializer
Для сериализации объектов в файлы xml
используется класс XmlSerializer. Он
предполагает некоторые ограничения:
- класс, подлежащий сериализации, должен
иметь стандартный конструктор без
параметров;
- сериализации подлежат только открытые
члены;
- если в классе есть поля или свойства с
модификатором private, то при сериализации
они будут игнорироваться;
27
- XmlSerializer требует указания типа.

28.

Пример 6
using System;
using System.IO;
using System.Xml.Serialization; // для сериализации
namespace Serialization{
// класс и его члены объявлены как public
[Serializable]
public class Person {
public string Name { get; set; }
public int Age { get; set; }
public Person() { } // конструктор без параметров
public Person(string name, int age) {
Name = name;
Age = age;
}
28
}

29.

Пример 6
class Program {
static void Main(string[] args) {
// объект для сериализации
Person person = new Person("Tom", 29);
// передать в конструктор тип класса
XmlSerializer formatter = new
XmlSerializer(typeof(Person));
// получение потока, куда будет
// записываться сериализованный объект
using (FileStream fs = new FileStream("persons.xml",
FileMode.OpenOrCreate)) {
formatter.Serialize(fs, person);
Console.WriteLine("Объект сериализован"); 29
}

30.

Пример 6
// десериализация
using (FileStream fs = new FileStream("persons.xml",
FileMode.OpenOrCreate)) {
Person newPerson =
(Person)formatter.Deserialize(fs);
Console.WriteLine("Объект десериализован");
Console.WriteLine("Имя: {0} --- Возраст: {1}",
newPerson.Name, newPerson.Age);
}
Console.ReadLine();
}
}
}
30

31.

Пример 7
using System;
using System.IO;
using System.Xml.Serialization; // для сериализации
namespace Serialization{
[Serializable]
public class Person {
public string Name { get; set; }
public int Age { get; set; }
public Company Company { get; set; }
public Person() { } // конструктор без параметров
public Person(string name, int age, Company comp) {
Name = name; Age = age; Company = comp;
}
31
}

32.

Пример 7
[Serializable]
public class Company {
public string Name { get; set; }
public Company() { } // конструктор без параметров
public Company(string name) {
Name = name;
}
}
class Program {
static void Main(string[] args) {
Person person1 = new Person("Tom", 29, new
Company("Microsoft"));
Person person2 = new Person("Bill", 25, new
Company("Apple"));
32
Person[] people = new Person[] { person1, person2 };

33.

Пример 7
XmlSerializer formatter = new XmlSerializer(typeof(Person[]));
using (FileStream fs = new FileStream("people.xml",
FileMode.OpenOrCreate)){ formatter.Serialize(fs, people); }
using (FileStream fs = new FileStream("people.xml",
FileMode.OpenOrCreate)) {
Person[] newpeople = (Person[])formatter.Deserialize(fs);
foreach (Person p in newpeople) {
Console.WriteLine("Имя: {0} --- Возраст: {1} --Компания: {2}", p.Name, p.Age, p.Company.Name);
}
}
Console.ReadLine();
}
}
}
33

34.

Сериализация в JSON. DataContractJsonSerializer
Для сериализации объектов в формат JSON в
пространстве
System.Runtime.Serialization.Json определен
класс DataContractJsonSerializer.
Чтобы задействовать этот класс, в проект надо
добавить сборку
System.Runtime.Serialization.dll.
Для записи объектов в json-файл в этом классе
имеется метод WriteObject(), а для чтения
ранее сериализованных объектов метод ReadObject().
34

35.

Пример 8
using System.Runtime.Serialization.Json;
using System.Runtime.Serialization;
namespace Serialization{
[DataContract]
public class Person {
[DataMember]
public string Name { get; set; }
[DataMember]
public int Age { get; set; }
[DataMember]
public Company Company { get; set; }
public Person() { }
public Person(string name, int age, Company comp) {
Name = name; Age = age; Company = comp;
}
}
35

36.

Пример 8
public class Company {
public string Name { get; set; }
public Company() { }
public Company(string name) {
Name = name;
}
}
class Program {
static void Main(string[] args) {
Person person1 = new Person("Tom", 29, new
Company("Microsoft"));
Person person2 = new Person("Bill", 25, new
Company("Apple"));
Person[] people = new Person[] { person1, person2 };
36

37.

Пример 8
DataContractJsonSerializer jsonFormatter = new
DataContractJsonSerializer(typeof(Person[]));
using (FileStream fs = new FileStream("people.json",
FileMode.OpenOrCreate)) { jsonFormatter.WriteObject(fs, people); }
using (FileStream fs = new FileStream("people.json",
FileMode.OpenOrCreate)) {
Person[] newpeople = (Person[])jsonFormatter.ReadObject(fs);
foreach (Person p in newpeople) {
Console.WriteLine("Имя: {0} --- Возраст: {1} --- Компания:
{2}", p.Name, p.Age, p.Company.Name);
}
}
Console.ReadLine();
}
}
37
}

38.

Обработка временных данных
Программист может сообщить сериализатору, что некоторые
данные сохранять не надо (экономия места на диске при
увеличении времени восстановления данных).
Соответствующие элементы следует пометить атрибутом
[NonSerialized]:
[NonSerialized] private int[] theSums;
Необходимо заметить, что если массив не будет сохранен, то
при восстановлении объекта результат окажется не вполне
корректным. Массив будет пуст.
Чтобы полностью восстановить объект перед возвращением его
вызвавшему объекту, следует реализовать интерфейс
IDeserializationCallback.
Среда CLR гарантирует программисту, что если он реализует
этот интерфейс, то она вызовет метод OnDeserialization() по
окончании восстановления всего объектного графа.
38

39.

Пример 9
namespace Programming_CSharp {
using System; // Работа с несериализованным объектом
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
[Serializable]
class SumOf : IDeserializationCallback {
public static void Main() {
Console.WriteLine("Создание первого с новым...");
SumOf app = new SumOf(1, 5);
Console.WriteLine(" Создание второго с
десериализацией...");
SumOf newInstance = SumOf.DeSerialize();
newInstance.DisplaySums();
}
39

40.

Пример 9
public SumOf(int start, int end) {
startNumber = start;
endNumber = end;
ComputeSums();
DisplaySums();
Serialize();
}
private void ComputeSums() { // заполнение массива
int count = endNumber - startNumber + 1;
theSums = new int[count];
theSums[0] = startNumber;
for (int i=1, j=startNumber + 1; i < count; i++, j++) {
theSums[i] = j + theSums[i-1];
}
}
}
40

41.

Пример 9
private void DisplaySums() {
foreach(int i in theSums) { Console.WriteLine("{0}, ",i); }
}
private void Serialize() {
Console.Write(" Сериализация...");
// создать файловый поток для записи
FileStream fileStream = new FileStream("DoSum.out",
FileMode.Create);
// воспользоваться двоичным форматизатором
BinaryFormatter binaryFormatter = new BinaryFormatter();
// сохранить объект на диске
binaryFormatter.Serialize(fileStream,this);
Console.WriteLine("...завершена");
fileStream.Close();
41
}

42.

Пример 9
public static SumOf DeSerialize() {
FileStream fileStream = new FileStream("DoSum.out",
FileMode.Open);
BinaryFormatter binaryFormatter = new
BinaryFormatter();
return (SumOf) binaryFormatter.Deserialize(fileStream);
fileStream.Close(); // восстановить несохраненную информацию
}
public virtual void Deserialization (Object sender) {
ComputeSums(); // Реализация интерфейса
}
private int startNumber = 1;
private int endNumber;
[NonSerialized] private int[] theSums;
42
}

43.

Изолированная память
Среда
.NET
CLR
предоставляет
механизм
изолированной
памяти
(Isolated
Storage),
позволяющий программисту хранить информацию
отдельно по каждому пользователю.
Изолированная память во многом напоминает
традиционные .ini-файлы Windows или более поздний
ключ HKEY_CURRENT_USER в реестре Windows.
Приложения сохраняют данные в уникальных отсеках
(data
compartments),
связанных
с
этими
приложениями. Среда CLR реализует отсеки данных с
помощью хранилищ (data stores), как правило, это
каталоги файловой системы.
43

44.

Изолированная память
Важно, что для хранения данных в изолированной памяти среда
CLR отводит стандартное место, но она не выдвигает никаких
требований относительно формата этих данных. Короче говоря,
в изолированной памяти можно хранить все, что угодно.
В большинстве случаев там хранится текст, часто в форме пар
«имя/значение». Изолированная память представляет собой
хорошее средство сохранения информации о пользовательской
конфигурации, то есть имени для входа в систему, координат
окон и элементов управления, а также сведений, специфичных
для конкретного пользователя и конкретного приложения.
Данные по каждому пользователю хранятся в отдельных
файлах, но степень изоляции можно повысить еще больше,
если проводить различие между отдельными аспектами
идентификации кода (по сборке или по домену приложения, из
которого исходит машинный код).
44

45.

Пример 10
namespace Programming_CSharp {
using System; // Запись в изолированную память
using System.IO;
using System.IO.IsolatedStorage;
public class Tester {
public static void Main() {
Tester app = new Tester();
app.Run();
}
private void Run() {
// создать поток для файла конфигурации
IsolatedStorageFileStream configFile = new
IsolatedStorageFileStream ("Tester.cfg",
FileMode.Create);
45

46.

Пример 10
// создать объект, пишущий в этот поток
StreamWriter writer = new StreamWriter(configFile);
// вывести данные в файл конфигурации
System.DateTime currentTime = System.DateTime.Now;
String output = "Last access: " + currentTime.ToString();
writer.WriteLine(output);
output = "Last position = 27,35";
writer.WriteLine(output);
writer.Flush(); // освободить буфер и закончить работу
writer.Close();
configFile.Close();
}
}
}
46

47.

Изолированная память
Изолированная память существует в пределах
сборки, то есть после перезапуска программы
можно будет обратиться к тому же
конфигурационному файлу.
Например, для чтения данных из
изолированной памяти следует заменить метод
Run() предыдущего примера 10,
перекомпилировать и запустить его (но не
менять его имя, иначе доступ к созданной ранее
изолированной памяти будет утерян) (пример
11 далее).
47

48.

Пример 11
private void Run( ) {/* Чтение данных из изолированной памяти */
// открыть поток конфигурационного файла
IsolatedStorageFileStream configFile = new
IsolatedStorageFileStream ("Tester.cfg", FileMode.Open);
// создать стандартный объект, читающий из потока
StreamReader reader = new StreamReader(configFile);
// считать файл и отобразить его
string theEntry;
do {
theEntry = reader. ReadLine( );
Console.WriteLine(theEntry);
} while (theEntry != null);
reader.Close( );
48
configFile.Close( );
}

49.

Контрольные вопросы
1. Для чего нужна сериализация?
2. Какие форматы сериализации
существуют?
3. Каков общий механизм сериализации?
49
English     Русский Rules