Предыстория


Все началось с того, что стал писать простенькую программу, которая должна была выполнять функции телефонного справочника. В качестве основного компонента, в котором будут размещаться все данные, выбрал объект класса ListView. Но любая хорошая программа должна уметь сохранять все свои данные в отдельный файл, с последующей его загрузкой, для продолжения работы с данными.

Что бы не изобретать велосипед, я принял решение о сохранение данных в XML-файл. Такой тип файла, очень удобен и популярен у многих разработчиков, с ним легко работать. Единственным его недостатком является слабая защищенность данных. Его можно открыть любым простым редактором текста, хотя и можно применить шифрование текста — это не гарантирует полной безопасности для информации в файле.

Как осуществить экспорт данных?


image

Как видно из скриншота, в элементе меню «Файл» уже все заготовлено для Экспорта и Импорта нашей телефонной книги, осталось написать сам код.

При написании данной программы, у меня еще не было практического опыта работы с XML-файлами на языке С# под платформой .NET. Поэтому я стал искать материал на просторах интернета. Но все мои результаты поисков были не утешительные. Все найденные результаты давали очень грубый и «макаронный» код, который можно адаптировать под свои нужды. Однако, это все же не практично. Такой код не возможно легко использовать в разных проектах.

После чего я решил углубиться в саму особенность работы с XML-файлами на языке C#.

Адаптивный код


Я обратил свое внимание на учебное пособие по языку С#, написанное Михаилом Фленовым, "Библия C#. 2-е издание". В своей книге, автор часто рекомендует и настаивает на полном использовании классов. А в теме, посвященной работе с XML-файлами, что бы экспортировать и импортировать данный использует «соответствующие» методы, которые являются методами класса того объекта, с которым работает.

Такой способ очень хороший, при условии, когда мы лично пишем класс объекта, с которым будем работать. А как быть в тех случаях, когда мы использует уже готовый класс? К примеру, класс ListView или Datagridview, мы их не писали (лично), но многие из нас часто ими пользуются.

В этот момент, я понял, что нужно создавать свой класс который, я всегда смогу использовать. Так мне не нужно (в будущем) все время тратить на описывание различных параметров. Нужно лишь будет переопределить методы класса, или просто сделать правки.

Класс для работы с XML


Код класса для работы с XML
public class Stroka
    {
        public void Main(string el1, string el2, string el3, string el4)
        {
            El1 = el1;
            El2 = el2;
            El3 = el3;
            El4 = el4;
        }

        public string El1 { get; set; }
        public string El2 { get; set; }
        public string El3 { get; set; }
        public string El4 { get; set; }

        public void SaveToFile(XmlTextWriter xmlOut)
        {
            xmlOut.WriteStartElement("Строка");
            xmlOut.WriteAttributeString("Колонка1", El1.ToString());
            xmlOut.WriteAttributeString("Колонка2", El2.ToString());
            xmlOut.WriteAttributeString("Колонка3", El3.ToString());
            xmlOut.WriteAttributeString("Колонка4", El4.ToString());
            xmlOut.WriteEndElement();
        }
        public void LoadFromFile(XmlTextReader xmlin)
        {
            try
            {
                El1 = xmlin.GetAttribute("Колонка1");
                El2 = xmlin.GetAttribute("Колонка2");
                El3 = xmlin.GetAttribute("Колонка3");
                El4 = xmlin.GetAttribute("Колонка4");
            }
            catch(Exception)
            { }
        }
    }


Для работы данного класса потребуется подключить еще две сборки:

using System.IO;
using System.Xml;

Класс я решил назвать "Stroka", это потому что мы в цикле будем перебирать все строки нашей таблице. Также обратите, что во всех частях кода описывается по 4 элемента. Это сделано намеренно. Количество элементов должно совпадать с нашим количество колонок, в таблице.

Так как наш класс готов, то мы можем его свернуть в нашем проекте, и больше в него не заглядывать.

Красивый экспорт (сохранение)


Давайте не будем спешить закончить нашу работу. А напишем еще несколько строчек кода, которые позволят нам вызывать диалоговое окно для сохранения.

image

Это окно мы сможем вызвать вот таким кодом:

Код вызова окна
private void экспорттелефоннойКнигиToolStripMenuItem_Click(object sender, EventArgs e)
        {
            int count = listView1.Items.Count;
            if (count == 0)
            {
                MessageBox.Show("Список Пуст. Нечего экспортировать.");
                return;
            }

            if (filename == "")
            {
                SaveFileDialog fileDialog = new SaveFileDialog();
                fileDialog.Title = "Экспорт";
                fileDialog.Filter = "XML files|*.xml";
                if (fileDialog.ShowDialog() != DialogResult.OK)
                    return;

                filename = fileDialog.FileName;
                Export();
            }
        }


Как вы могли заметить, это уже метод экспорта данных в XML-файл. Но здесь ничего интересного не происходит, только вызывается окно для экспорта, и его путь записывается в переменную "filename". Это обычная строковая переменная, которая создается еще в начале проекта.

Выглядит это так:

Пример
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Xml;

namespace TestPhoneBook
{
    public partial class MainWindow : Form
    {
        string filename = "";

        public MainWindow()
        {
            InitializeComponent();
        }
...


Сам экспорт выполнится в методе «Export();».

Время метода «Export();»


Код метода Export()
 public void Export()
        {
            //создание потока записи и объекта создания  xml-документа
            FileStream fs = new FileStream(filename, FileMode.Create);
            XmlTextWriter xmlOut = new XmlTextWriter(fs, Encoding.Unicode);

            xmlOut.Formatting = Formatting.Indented;

            //старт начала документа
            xmlOut.WriteStartDocument();
            xmlOut.WriteComment("Тестовое задание. Телефонная книга");
            xmlOut.WriteComment("Работу выполнил: Григорий Чуприна");

            //создание корневого документа
            xmlOut.WriteStartElement("PhoneBook");
            xmlOut.WriteAttributeString("Version", "1.0.0");

            //цикл перебора всех элементов
            int count = listView1.Items.Count;

            for (int t = 0; t < count; t++)
            {
                ListViewItem item = listView1.Items[t];
                Stroka stroka = new Stroka();
                stroka.Main(item.SubItems[0].Text, item.SubItems[1].Text, item.SubItems[2].Text, item.SubItems[3].Text);
                stroka.SaveToFile(xmlOut);
            }

            //закрытие основного тега и документа
            xmlOut.WriteEndElement();
            xmlOut.WriteEndDocument();

            //закрытие объекта записи
            xmlOut.Close();
            fs.Close();
        }


Важно заметить, что большая часть этого кода «шаблонна», для многих наших проектов с этим классом, единственной отличительной чертой всегда будет наш «цикл перебора всех элементов». Он будет отличаться в зависимости от того, с какой «таблицы» мы будем экспортировать данный. В данном случае, данные берутся с объекта класса ListView.

Обратите внимание на строчки:

Stroka stroka = new Stroka();
                stroka.Main(item.SubItems[0].Text, item.SubItems[1].Text, item.SubItems[2].Text, item.SubItems[3].Text);

Мы создаем объект класса (нашего) Stroka, и в его метод Main помещаем элементы строки (4-х наших колонок).

Экспорт завершен


image

Созданный XML-файл я открыл программой «Блокнот», и мы можем сравнить структуру файла с нашим кодом.

Наш класс позволяет также импортировать данные, в наше приложение. Мы также сможем редактировать, и выполнять любую другую работу с ними так, как будто данные изначально были в программе.

Но об этом в другой публикации.
Поделиться с друзьями
-->

Комментарии (21)


  1. lair
    14.12.2016 17:37
    +5

    Вы, простите, про xml-сериализацию не слышали?


    1. napa3um
      14.12.2016 17:46
      +6

      Вся статья похожа на переутолщённый прикол (и шрифт какой на картинке, и замазанное название XML-файла, и имя класса Stroka, и «защищённость данных», и всё остальное).


      1. lair
        14.12.2016 17:47

        xmlOut.WriteComment("Тестовое задание. Телефонная книга");
        xmlOut.WriteComment("Работу выполнил: Григорий Чуприна");


        1. KvanTTT
          14.12.2016 19:34

          Мы вам перезвоним… ©


  1. Varim
    14.12.2016 17:41

    public class Stroka
    String щас заругают.
    Про reflection и t4 (*.tt) думали?


  1. impwx
    14.12.2016 17:42
    +16

    Как только увидел курсив на скриншоте, так и знал, что внутри тоже будет жесть. И как в воду глядел!


  1. AgentSmith
    14.12.2016 17:47
    +6

    У меня возникло сильное желание кого-нибудь ударить.
    Статья выглядит как чей-то троллинг


  1. ls18
    14.12.2016 18:03
    +3

    Да не похоже на троллинг. Видимо парнишка начинающий и не совсем угадал с тематикой поста для Песочницы. Многие из нас такими были.


    1. IlyaMS
      15.12.2016 12:20

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


      1. vlreshet
        15.12.2016 13:34

        Тут не сыроват — тут и готовить то нечего)


  1. vlreshet
    14.12.2016 18:05
    +2

    Тот случай когда увидел пост в фиде, и даже не читая его учуял неладное.


  1. GennPen
    14.12.2016 18:16

    Это уже не смешно.
    На месте препода я бы поставил «неуд.» и заставил все переписывать.

    private void экспорттелефоннойКнигиToolStripMenuItem_Click(object sender, EventArgs e)


  1. Gray_Wolf
    14.12.2016 18:26
    +2

    private void экспорттелефоннойКнигиToolStripMenuItem_Click(object sender, EventArgs e)

    Личинка программиста 1С?

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.IO;
    using System.Xml;

    Я не знаток .NET, но для телефонного справочника действительно всё это необходимо?


    1. IvaYan
      14.12.2016 18:38
      +2

      Там половина того, что Visual Studio подключает автоматически. В частности Linq, Tasks, Drawing. Их можно убрать, но автор этого не сделал.


      private void экспорттелефоннойКнигиToolStripMenuItem_Click(object sender, EventArgs e)

      Личинка программиста 1С?

      Это тоже от студии. При создании она называет пункт меню из того текста, которые в этот пункт вписан.


      1. dobriykot
        14.12.2016 19:39

        Тулстрип с именем «экспорттелефоннойКниги» не студия придумала.


        1. IvaYan
          14.12.2016 19:56
          +3

          Студия взяла название из текста от пункта.


  1. aulandsdalen
    14.12.2016 20:46

    эмейл [x]


  1. GoldenStar
    15.12.2016 00:25
    -1

    В свое время:
    1) использовал для вывода данных на экран DataGridView, а не ListView
    2) сохранял таблицу в XML стандартной командой и восстанавливал в DataGridView тоже одной! командой.
    3) код для редактирования/добавления данных вообще практически писать не надо — все есть в элементе управления
    4) можно отображать связанные таблицы — крайне удобно например при создании динамических иерархических меню и т.п.
    Проще некуда если честно.

    Объекты можно серилизовать — очень просто делается если поискать в интернете:
    public class XmlSerializationHelper
    {
    public static void Serialize(string filename, T obj)
    {
    XmlSerializer xs = new XmlSerializer(typeof(T));
    using (StreamWriter wr = new StreamWriter(filename))
    {
    xs.Serialize(wr, obj);
    }
    }

    public static T Deserialize(string filename)
    {
    XmlSerializer xs = new XmlSerializer(typeof(T));
    using (StreamReader rd = new StreamReader(filename))
    {
    return (T)xs.Deserialize(rd);
    }
    }
    }


  1. DreamChild
    15.12.2016 00:49
    +4

    Это творчество должно подпадать под статью о распространении порнографии. А то и под оскорбление чувств верующих в красивый код. Лет пять с конфискацией клавиатуры за такое, не меньше.


  1. petuhov_k
    15.12.2016 05:00

    Похоже, что автор не дотерпел до 1 апреля. i_am_psionic признавайся, это юмор или нет. Не могу решить какую стрелочку кликнуть.


  1. HabrDev
    22.12.2016 13:12

    Автор, совет на будущее: Не используйте WinForms, или хотя бы разделяйте UI и бизнес-логику, организовывая таким образом правильную архитектуру проекта.Для этого вполне должен подойти паттерн MVP. И да, как было подмечено выше, придется отучиться от пагубной привычки именовать идентификаторы транслитерацией.