Раздел 10. Глава 9. Собственная база данных на основе XML файлаВведениеКогда создаются программы, использующее одну или несколько таблиц баз данных и (или) таблицы базы данных требуются только одному приложению (ограниченному числу приложений), то достаточно неудобно при сопровождении приложения отслеживать установки клиентского программного обеспечения для работы с базами данных, выполнять соответствующие настройки, решать вопросы безопасности и т.д. и т.п. В Borland C++ Builder (Borland Delphi) для таких ситуаций можно использовать компонент TClientDataSet, позволяющий создать из таблиц БД файл, который далее использовать в приложении полностью аналогично таблице базы данных. Собственно компонент TCLientDataSet позволял также, после загрузки файла из реальной таблицы БД, забыть на время о сервере доступа к данным и работать только с этим файлом (выполнять любое редактирование), а на этапе завершения приложения или на этапе необходимости публикации данных - перенести нужные данные в реальную таблицу БД. В Visual Studio Net контрола, или элемента подобного компоненту TCLientDataSet, нет. Но все, что позволял компонент TCLientDataSet с таким же успехом можно выполнить, используя XML файлы. Мы уже пользовались возможностью загрузки данных из таблиц БД в DataSet и обратного сохранения данных. В данной главе мы будем использовать загрузку данных из XML файла в DataSet, отметив, что после загрузки данных, доступ к данным ничем не отличается от работы с данными при их загрузке из таблиц БД. Учитывая возможность работы с двоичными данными, описанную в предыдущей главе, мы можем непосредственно приступить к описанию создания собственной базы данных на основе XML файла и работы с ней. Параграф 1. Создание файла базы данныхXML файл базы данных может быть создан на основе реальной таблицы базы данных. Для этого необходимо загрузить DataSet данными реальной таблицы (как это сделать - см. "Основы работа с сервером SQL в Visual Studio .NET" и "Работа с сервером SQL в Visual Studio 2005 (ASP.NET 2)") и сохранить DataSET как XML файл. Второй вариант, создать заготовку файла в текстовом редакторе (см. предыдущую главу "Параграф 2. Сохраняем рисунок в XML файл"). Пойдем по второму пути и, как и в предыдущей главе, сначала создадим простое решение приложения, имеющее три кнопки (три контрола Button на форме, пока без обработчиков событий нажатия кнопок), контрол PictureBox, три контрола TextBox, контрол OpenFileDialog и несколько контролов Label (Рис.1.). Наше решение будет предназначено для подготовки информации к выставке собак и показе информации на самой выставке (естественно, что это упрощенное решение).
Рис.1 Решение приложения Выполним решение в режиме Release. В директорию, где будет сформирован exe файл приложения (у меня C:\Samples_C#_2008\WindowsFormsApplication2\bin\Release\), поместим XML файл (хотя поместить файл можно и куда угодно на жестком диске). Пусть это будет файл с именем sales1.xml, а его содержимое - данные о собачках, подготовленных к продаже неким обществом, этим занимающимся: <?xml version="1.0" encoding="windows-1251"?> <NewDataSet> <dog> <id></id> <name></name> <pic></pic> <picext></picext> <price></price> </dog> </NewDataSet> Первая строка XML документа называется объявлением XML (declaration) это необязательная строка, указывающая версию стандарта XML. Здесь может быть указана кодировка символов (encoding="windows-1251") и внешние зависимости. Заголовок может содержать атрибут "самодостаточности". Указание кодировки символов, к сожалению, является обязательным. DataSet при загрузке в него XML документов учитывает информацию мегатэгов, но нигде ее не сохраняет и, поэтому, добавление метатэга с параметром "encoding" придется выполнять ручками при сохранении документа или использовать сохранение документа с записью его схемы (оба способа показаны ниже). Обратим внимание на тэг "NewDataSet". Поскольку мы работаем с DataSet, то при сохранении содержимого DataSet в XML файл, данный тэг добавляется автоматически. Кроме этого файл имеет тэги "dog" - один на каждый экземпляр, "id" - идентифицирующий номер записи, "name" - имя собачки, "pic" - рисунок, "picext" - формат рисунка и "price" - цена. Параграф 2. Загрузка XML файла, ввод и сохранение данныхВ начале определим все глобально используемые в пределах приложения переменные:
public partial class Form1 : Form
{
//Директория выполнения приложения
private string sCurDir = string.Empty;
//Класс XML документа
private XmlDocument xmldoc = null;
//Классы для работв с XML документом как с объектом базы данных
DataTable MyDatatable = null;
DataSet MyDataSet = null;
В обработчике события Load формы будем выполнить начальную загрузку XML файла:
private void Form1_Load(object sender, EventArgs e)
{
sCurDir = Directory.GetCurrentDirectory();
label1.Text = "";
label2.Text = "";
using (StreamReader streamreader = new StreamReader(sCurDir + @"\sales1.xml",
System.Text.Encoding.UTF8))
{
MyDataSet = new DataSet();
MyDataSet.ReadXml(streamreader, XmlReadMode.Auto);
MyDatatable = MyDataSet.Tables[0];
}
}
Обратим внимание на параметр метода ReadXml "XmlReadMode.Auto" - он позволит DataSet правильно создать схему с учетом значений мегатэгов, а также на значение "Encoding.UTF8". Причина использования именно этой кодировки - DataSet по умолчанию будет сохранять данные в кодировке UTF8. Итак, на данном этапе, пустой XML файл загружен в DataSet с именем MyDataSet. Выполним выбор рисунка в PictureBox для его последующего сохранения в файл и ввод имени и цены в контролы TextBox, для чего используем следующие обработчики событий:
private void button2_Click(object sender, EventArgs e)
{
openFileDialog1.InitialDirectory = sCurDir;
openFileDialog1.Filter = "gif files(*.gif)|*.gif|bmp files(*.bmp)|*.bmp";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
pictureBox1.Image = Image.FromFile(openFileDialog1.FileName);
//Расширение сохраняем в TextBox4
textBox4.Text = Path.GetExtension(openFileDialog1.FileName);
}
}
//Цена в TtextBox3 может быть только цифра
private void textBox3_KeyPress(object sender, KeyPressEventArgs e)
{
if (!Char.IsDigit(e.KeyChar))
{
e.Handled = true;
}
}
Осталось сохранить данные.
private void button3_Click(object sender, EventArgs e)
{
//Сохранять не будем - если что-то не ввели
if (pictureBox1.Image == null) return;
if (textBox4.Text == "") return;
if (textBox2.Text == "") return;
if (textBox3.Text == "") return;
//Строки для метода Select в XML документе
DataRow[] datarows = null;
//Ищем максимальное ID в DataSet (в Datatable)
string s = string.Empty;
try
{
datarows = MyDatatable.Select("id=max(id)");
s = datarows[0]["id"].ToString();
}
catch (Exception)
{
}
if (s == "" || s == string.Empty)
{
s = "0";
}
//Для формирования строки рисунка создаем StringBuilder
StringBuilder MyStringBuilder = new StringBuilder();
int i = int.Parse(s)+1;
//Создаем новую строку для MyDataSet
DataRow datarow = MyDataSet.Tables[0].NewRow();
//Присваиваем значения столбцам строки
datarow[0] = Convert.ToString(i);
datarow[1] = textBox2.Text.Trim();
//Формируем строковое представление рисунка (см. предыдущую главу)
using (MemoryStream memorystream = new MemoryStream())
{
pictureBox1.Image.Save(memorystream, ImageFormat.Gif);
byte[] b = new byte[memorystream.Length];
//memorystream.Read(b, 0, (int)memorystream.Length);
b = memorystream.GetBuffer();
s = string.Empty;
foreach (Byte zb in b)
{
int a = (int)zb;
MyStringBuilder.Append(a.ToString("X2"));
}
datarow[2]=Convert.ToString(MyStringBuilder);
}
datarow[3] = textBox4.Text.Trim();
datarow[4] = textBox3.Text.Trim();
MyDataSet.Tables[0].Rows.Add(datarow);
//Удаляем строку с пустыми значениями, которые при первоначальной
//загрузке были использованы для формирования схемы
if (i == 1)
{
MyDataSet.Tables[0].DefaultView.AllowDelete = true;
MyDataSet.Tables[0].DefaultView.Delete(0);
}
pictureBox1.Image = null;
textBox4.Text="";
textBox3.Text="";
textBox2.Text="";
//Сохраняем данные
MyDataSet.WriteXml(sCurDir + @"\sales1.xml",XmlWriteMode.WriteSchema);
MyDataSet = new DataSet();
//Вновь загружаем сохраненные данные
MyDataSet.ReadXml(sCurDir + @"\sales1.xml",XmlReadMode.Auto);
MyDatatable = MyDataSet.Tables[0];
}
Файл XML будет иметь вид:
<?xml version="1.0" standalone="yes"?>
<NewDataSet>
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="dog">
<xs:complexType>
<xs:sequence>
<xs:element name="id" type="xs:string" minOccurs="0" />
<xs:element name="name" type="xs:string" minOccurs="0" />
<xs:element name="pic" type="xs:string" minOccurs="0" />
<xs:element name="picext" type="xs:string" minOccurs="0" />
<xs:element name="price" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="dog" />
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<dog>
<id>1</id>
<name>РЁР°С_РїРчР№ в"- 1</name>
<pic>474946383961C5006500F70000000000800000008000808000000080800080008..............</pic>
<picext>.gif</picext>
<price>2000</price>
</dog>
</NewDataSet>
Обратим внимание, что кодировка файла, как и предполагалось, "UTF8". Если мы хотим иметь файл нашей базы данных более читаемым, поступим следующим образом:
XML файл будет выглядеть следующим образом:
<?xml version="1.0" encoding="windows-1251" standalone="yes"?>
<NewDataSet>
<dog>
<id>1</id>
<name>Шарпей № 1</name>
<pic>474946383961C5006500F700000000008000000080008080000000........</pic>
<picext>.gif</picext>
<price>2000</price>
</dog>
<dog>
<id>2</id>
<name>Шарпей № 2</name>
<pic>474946383961C5006500F700000000008000000080008080000000........</pic>
<picext>.gif</picext>
<price>5000</price>
</dog>
</NewDataSet>
Параграф 3. Отображение данныхДанные загружаются при старте приложения и при сохранении новой записи в DataSet. С этого момента мы можем работать с ними как с данными, полученными с реальной таблице базы данных (см. "Основы работа с сервером SQL в Visual Studio .NET" и "Работа с сервером SQL в Visual Studio 2005 (ASP.NET 2)") В качестве примера приведем отображение данных по запросу. В качестве запроса будем использовать информацию о ID записи, которую будем вводить в TextBox1:
//ID может быть только цифра
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (!Char.IsDigit(e.KeyChar))
{
e.Handled = true;
}
}
private void button3_Click(object sender, EventArgs e)
{
if (textBox1.Text.Trim() != "")
{
textBox2.Text = "";
textBox3.Text = "";
textBox4.Text = "";
pictureBox1.Image = null;
getDog(textBox1.Text.Trim());
}
}
private void getDog(string num)
{
DataRow[] datarows = null;
try
{
datarows = MyDatatable.Select("id=" + num);
}
catch (Exception ex)
{
return;
}
if (datarows.Length > 0)
{
foreach (DataRow datarow in datarows)
{
label1.Text = datarow["name"].ToString();
string s3 = datarow["pic"].ToString();
label2.Text = "Цена: "+datarow["price"].ToString();
using (MemoryStream memorystream = new MemoryStream())
{
for (int i = 0; i < s3.Length / 2; i++)
{
if (i * 2 + 1 < s3.Length)
{
string s02 = Convert.ToString(s3[i * 2]);
string s03 = Convert.ToString(s3[i * 2 + 1]);
string s04 = s02 + s03;
int a = int.Parse(s04, System.Globalization.NumberStyles.HexNumber);
memorystream.WriteByte(Convert.ToByte(a));
}
}
pictureBox1.Image = Image.FromStream(memorystream);
}
}
}
}
}
Обратим внимание на формат рисунка (документа). Мы уже отмечали, что точно таким образом можно сохранять и восстанавливать любые данные (Web страницы, Word или Excel документы и т.д. и т.п...). При отображении, сохранении и преобразованиях эта информация нами может быть использована. Что касается рисунков, то подробно о преобразованиях форматов можно посмотреть в главе О возможностях преобразований графических файлов при их отображении на сайте (все что касается преобразований равным образом относится к Web и Windows решениям).
Рис.2 Выполнение приложения И последнее замечание. Описанный способ работы с XML данным с использованием DataSet может быть удобной заменой ini-фалов приложений. По крайней мере, доступ к строке параметра по имени в DataSet значительно проще, чем его позиционный или лексический поиск в ini-файле. Молчанов Владислав 16.12.2007г. Еcли Вы пришли с поискового сервера - посетите мою главную страничкуНа главной странице Вы найдете программы комплекса Veles - программы для автолюбителей,
программу NumberPhoto, созданную для работы с фото, сделанными цифровым фотоаппаратом,
программу Локальный Web сайт - предназначенную для просмотра и прослушивания
файлов большинства графических и звуковых форматов в Web Browser,
программу Bricks - игрушку для детей и взрослых, программу записную книжку,
программу TellMe - говорящий Русско-Английский разговорник - программу для тех, кто собирается
погостить за бугром или повысить свои знания в английском, теоретический материал
по программированию в среде Borland C++ builder, C# (Windows приложения и ASP.Net Web сайты).
|