лекция. Зиборов. Справочник для опытных и как пособие для начинающих программистов. Компактдиск содержит исходные коды примеров из книги
Скачать 7.39 Mb.
|
Глава 4 Чтение, запись текстовых и бинарных файлов, текстовый редактор Пример 23. Чтение/запись текстового файла в кодировке Unicode. Обработка исключений try...catch Очень распространенной задачей является сохранение данных на диске в текстовом формате (не в двоичном). В этом случае сохраненные данные можно читать, редактировать любым текстовым редактором, например Блокнотом или TextEdit. Читать текстовые данные также можно и в своей программе. Казалось бы, это очень простая задача. Например, чтение текстового файла сводится буквально к нескольким строчкам: // Создание экземпляра StreamReader для чтения из файла System.IO.StreamReader Reader = new System.IO.StreamReader("C:WTextl.txt"); // Считывание содержимого текстового файла в строку String Stroka = Reader.ReadToEndО; Reader.Close(); Однако есть некоторые серьезные нюансы. Напишем программу, содержащую на экранной форме текстовое поле и две командные кнопки. При щелчке мышью на первой кнопке происходит чтение текстового файла в текстовое поле в кодировке Unicode. При щелчке на второй кнопке отредактированный пользователем текст в текстовом поле сохраняется в файл на диске. Запустим среду Visual Studio 2010 и закажем новый проект шаблона Windows Forms Application С#. Далее в форму перенесем текстовое поле и две командные копки. Для текстового поля в окне Properties сразу укажем для свойства Multiline значение True, чтобы текстовое поле имело не одну строку, а столько, сколько поместится в растянутом указателем мыши поле. Одна кнопка предназначена для открытия файла, а другая — для сохранения файла на машинном носителе. В листинге4.1 приведен текст данной программы. Листинг 4.1. Чтение/запись текстового файла в кодировке Unicode // Программа для чтения/записи текстового файла в кодировке Unicode using System.Windows.Forms; // Другие директивы using удалены, поскольку они не используются в данной программе namespace TXT_Unicode { public partial class Form1 : Form { string filename = @"C:\Textl.txt"; public Form1() { InitializeComponent(); textBox1.Multiline = true; textBoxl.Clear(); textBox1.Tablndex =0; ' textBox1.Size = new System.Drawing.Size(268, 112); button1.Text = "Открыть"; button1.Tablndex = 0; button2.Text = "Сохранить"; base.Text = "Здесь кодировка Unicode"; } private void button1_Click(object sender, System.EventArgs e) { // Щелчок на кнопке "Открыть". // Русские буквы будут корректно читаться, // если файл в кодировке UNICODE: try { // Создание объекта StreamReader для чтения из файла: var Читатель = new System.10.StreamReader(filename); // Непосредственное чтение всего файла в текстовое поле: textBox1.Text = Читатель.ReadToEnd(); Читатель.Close(); // закрытие файла // Читать текстовый файл в кодировке UNICODE в массив строк // можно также таким образом (без Open и Close): // string[] МассивСтрок = System.IO. // File.ReadAllLines(@"C:\Textl.txt"); } catch (System.IO.FileNotFoundException Ситуация) { // Обработка исключительной ситуации: MessageBox. Show (Ситуация.Message + “\nНет такого файла”, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } catch (System.Exception Ситуация) { // Отчет о других ошибках: MessageBox.Show(Ситуация.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } } private void button2_Click(object sender, System.EventArgs e) { // Щелчок на кнопке Сохранить: Try { // Создание объекта StreamWriter для записи в файл: var Писатель = new System.10.StreamWriter(filename, false); Писатель . Write (textBoxl. Text) ; Писатель.Close(); // Сохранить текстовый файл можно также таким образом // (без Close), причем, если файл уже существует, // то он будет заменен: // System.10.File.WriteAllText(@"С:\tmp.tmp", textBoxl.Text); } catch (System.Exception Ситуация) { // Отчет обо всех возможных ошибках: MessageBox.Show(Ситуация.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } } } } Несколько слов о блоках try, которые, как видно, используются в данном программном коде. Логика использования try следующая: попытаться (try) выполнить некоторую задачу, например, прочитать файл. Если задача решена некорректно (например, файл не найден), то "перехватить" (catch) управление и обработать возникшую (исключительную, Exception) ситуацию. Как видно из текста программы, обработка исключительной ситуации свелась к информированию пользователя о недоразумении. При обработке события "щелчок на кнопке" Открыть организован ввод файла C:\Text1.txt. Обычно в этой ситуации пользуются элементом управления OpenFileDialog для выбора файла. Мы не стали использовать этот элемент управления для того, чтобы не "заговорить" проблему, а также свести к минимуму программный код. Далее создаем объект (поток) Читатель для чтения из файла. Для большей выразительности операций с данным объектом мы назвали его русскими буквами Затем следует чтение файла filename методом ReadToEnd() в текстовое поле textBox1.Text и закрытие файла методом Сlose (). При обработке события "щелчок на кнопке" Сохранить организована запись файла на диск аналогично через объект Писатель. При создании объекта Писатель первым аргументом является filename, а второй аргумент false указывает, что данные следует не добавить (append) к содержимому файла (если он уже существует), а перезаписать (overwrite). Запись на диск производится с помощью метода write() из свойства Text элемента управления textBox1. На рис. 4.1 приведен фрагмент работы программы. Рис. 4.1. Чтение/запись текстового файла в кодировке Unicode Сделаем очень важное примечание. Запись текстового файла с помощью данной программы будет происходить в формате (кодировке) Unicode, как и чтение из файла. То есть вы сможете читать эти файлы Блокнотом, редактировать их, но каждый раз при сохранении файлов следить; чтобы кодировка была Unicode. Однако по умолчанию в редакторах обычно используется кодировка ANSI. Кодировку ANSI с русскими буквами называют Windows 1251. Некоторые редакторы, например, RPad ("русский" Блокнот) вообще не работают с Unicode. Таким образом, на сегодняшний день пока что записывать в кодировке Unicode — это как бы эксклюзив. Возможно, даже наверняка, в ближайшее время многое изменится в пользу Unicode, поскольку информационные технологии меняются очень быстро. Если в Блокноте подготовить текстовый файл в обычной кодировке ANSI, то прочитать русские буквы данной программой не получится, хотя английские буквы отобразятся в текстовом поле без проблем. Почему? Дело в том, что приведенная в тексте данной программы технология описана в учебных пособиях по Visual С#, MSDN, на сайтах, подобных http://msdn.microsoft.com/library/rus/. Однако чаще это все англоязычные источники, а для английских текстов переход от одной кодировки к другой оказывается практически незаметным. Например, английские буквы кодировок Windows 1251, ASCII и Unicode совпадают, а с русскими буквами всегда возникают недоразумения. Об этом говорят программисты на различных форумах в Интернете. Программистам эти недоразумения следует учитывать. Разрешению этого недоразумения посвящена следующая программа. Убедиться в работоспособности данной программы можно, открыв решение TXT_Unicode.sln в папке TXT_Unicode. Пример 24. Чтение/запись текстового файла в кодировке Windows 1251 В данном примере также на экранной форме имеем текстовое поле и две командных кнопки, назначение этих элементов управления аналогично предыдущему примеру. Однако чтение и запись текстового файла в этом примере происходит в кодировке Windows 1251 (ANSI). Поскольку структура данной программы аналогична предыдущей, сразу обратимся к ее коду в листинге 4.2. Листинг 4.2. Чтение/запись текстового файла в кодировке Windows 1251 // Программа для чтения/записи текстового файла в кодировке Windows 1251 using System; using System.Windows.Forms; // Другие директивы using удалены, поскольку они не используются в данной программе namespace ТХТ_1251 { public partial class Form1 : Form { string filename = @"C:\Text2.txt"; public Form1() { InitializeComponent(); textBox1.Multiline = true; textBox1.Clear(); textBox1.Size = new System.Drawing.Size(268, 112); button1.Text = "Открыть"; button1.Tablndex = 0; button2.Text = "Сохранить"; this.Text = "Здесь кодировка Windows 1251"; } private void button1_Click(object sender, EventArgs e) { // Щелчок на кнопке Открыть try { // Чтобы русские буквы читались бы корректно, объявляем // объект Кодировка: var Кодировка = System.Text.Encoding.GetEncoding(1251); // Создание экземпляра StreamReader для чтения из файла var Читатель = new System.IO.StreamReader(filename, Кодировка); textBox1.Text = Читатель.ReadToEnd(); Читатель.Close(); // Читать текстовый файл в кодировке Windows 1251 в массив строк // можно также таким образом (без Open и Close): // string[] МассивСтрок = System.10. // File.ReadAllLines(@"С:\Text2.txt", Кодировка); } catch (System.IO.FileNotFoundException Ситуация) { // Обработка исключительной ситуации: MessageBox.Show(Ситуация.Message + "\пНет такого файла", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } catch (Exception Ситуация) { // Отчет о других ошибках MessageBox.Show(Ситуация.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } } private void button2_Click(object sender, EventArgs e) { // Щелчок на кнопке Сохранить: try { var Кодировка = System.Text.Encoding.GetEncoding(1251); // Создание экземпляра StreamWriter для записи в файл: var Писатель = new System.IO.StreamWriter(filename, false, Кодировка); Писатель.Write(textBox1.Text); Писатель.Close(); // Сохранить текстовый файл можно также таким образом (без Close) // причем, если файл уже существует, то он будет заменен: // System.IO.File.WriteAllText(@"С:\tmp.tmp", // textBox1.Text, Кодировка); } catch (System.Exception Ситуация) { // Отчет обо всех возможных ошибках: MessageBox.Show(Ситуация.Message, "Ошибка", MessageBoxButtons.OK, MessageBox1con.Exclamation); } } } } Этот текст программы отличается от предыдущего лишь тем, что здесь введен новый объект— Кодировка. Метод GetEncoding(1251) устанавливает кодовую страницу Windows 1251 для объекта кодировка. Можно убедиться в этом, если распечатать свойство Кодировка .HeaderName. При создании объекта Читатель используются уже два аргумента: имя файла filename и объект кодировка, указывающий, в какой кодировке (для какой кодовой страницы) читать данные из текстового файла. А при создании объекта Писатель используются три аргумента: имя файла filename, установка false (для случая, если файл уже существует, нужно будет не добавлять новые данные, а создавать новый файл) и объект Кодировка, указывающий, в какой кодировке писать данные в файл. Убедиться в работоспособности программы можно, открыв решение TXT_1251.sln в папке ТХТ_1251. Пример 25. Простой текстовый редактор. Открытие и сохранение файла. Событие формы Closing Итак, мы уже знаем, что существуют технологии чтения/записи текстового файла для нужной кодовой страницы. Таким образом, мы имеем основные компоненты для написания текстового редактора. Запустив систему Visual Studio 2010 и щелкцув по шаблону Windows Forms Application С#, перенесем из панели элементов управления Toolbox в форму текстовое поле TextBox и меню MenuStrip. Используя элемент управления MenuStrip, создадим один пункт меню Файл и три пункта подменю: Открыть, Сохранить как и Выход (рис. 4.2). Рис. 4.2. Простой текстовый редактор Из панели Toolbox нам понадобятся еще элементы управления OpenFileDialog и SaveFileDialog, также перенесем их в форму, хотя их очень легко объявить и использовать непосредственно в программном коде. Итоговый текст програм "Простой текстовый редактор" представлен в листинге 4.3, и автор заранее приносит свои извинения за слишком длинный программный код, однако короче нельзя! Ксати, чтобы увеличить количество строчек программного кода, который вы хотели бы одновременно видеть на экране, удобно пользоваться комбинацц клавиш <Shift>+Alt>+<Enter> (Full Screen). Листинг 4.3. Простой текстовый редактор // Простой текстовый редактор using System.Windows.Forms; // Другие директивы using удалены, поскольку они не используются в данной программе namespace TXT_edit { public partial class Form1 : Form { public Form1() { InitializeComponent(); textBox1.Multiline = true; textBox1.Clear(); textBox1.Size = new System.Drawing.Size(268, 160); this.Text = "Простой текстовый редактор"; openFileDialog1.FileName = @"C:\Text2.txt"; openFileDialog1.Filter = "Текстовые файлы (*.txt)|*.txt|All files (*.*)|*.*"; saveFileDialogl.Filter = "Текстовые файлы (*.txt)|*.txt|All files (*.*)|*.*"; } private void oткрытьToolStripMenuItem_Click(object sender, System.EventArgs e) { // Вывести диалог открытия файла openFileDialogl.ShowDialog(); if (openFileDialogl.FileName == null) return; // Чтение текстового файла: try { // Создание экземпляра StreamReader для чтения из файла var Читатель = new System.IO.StreamReader (openFileDialog1.FileName, System.Text.Encoding.GetEncoding(1251)); // - здесь заказ кодовой страницы Winl251 для русских букв textBox1.Text = Читатель.ReadToEnd(); Читатель.Close(); } catch (System.IO.FileNotFoundException Ситуация) MessageBox.Show(Ситуация + "\nНет- такого файла", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } catch (System.Exception Ситуация) { // Отчет о других ошибках MessageBox.Show(Ситуация.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } } private void coxpaнить КакToolStripMenuItem_Click(object sender, System.EventArgs e) { // Пункт меню "Сохранить как" saveFileDialog1.FileName = openFileDialog1.FileName; if (saveFileDialog1.ShowDialog() == DialogResult.OK) Запись(); } void Запись() { try { // Создание экземпляра StreamWriter для записи в файл: var Писатель = new System. IO.StreamWriter (saveFileDialogl.FileName, false, System.Text.Encoding.GetEncoding(1251)); // - здесь заказ кодовой страницы Winl251 для русских букв Писатель.Write(textBox1.Text); Писатель.Close(); textBox1.Modified = false; } catch (System.Exception Ситуация) { // Отчет обо всех возможных ошибках MessageBox.Show(Ситуация.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } } private void выходToolStripMenuItem_Click(object sender. System.EventArgs e) { this.Closed ; } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { if (textBox1.Modified == false) return; // Если текст модифицирован, то спросить, записывать ли файл? DialogResult МВох = MessageBox.Show( "Текст был изменен. \nСохранить изменения?", "Простой редактор", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Exclamation); // YES — диалог; NO — выход; CANCEL - редактировать if (МВох == DialogResult.No) return; if (MBox == DialogResult.Cancel) e.Cancel = true; if (MBox == DialogResult.Yes) { if (saveFileDialog1.ShowDialog() == DialogResult.OK) { Запись(); return; } else e.Cancel = true; // Передумал выходить из ПГМ } // DialogResult.Yes } } } Как видно их текста программы, сразу после завершения работы процедуры InitializeComponent присваиваем начальные значения некоторым переменным. В частности для открытия (Open) и сохранения (Save) файлов заказываем фильтр (Filter) для текстовых файлов *. txt, а также для всех файлов *. *. При обработке события "щелчок на пункте меню" Открыть выводим стандартный диалог открытия файлов OpenFileDialog, и если полученное в результате диалога имя файла не пусто (null), то организуем чтение текстового файла. Эта процедура в точности соответствует процедуре чтения файла из предыдущего раздела, разве что упрощен заказ на чтение в кодировке Windows 1251. Аналогично написана обработка события "щелчок на пункте меню" Сохранить как (см. рис. 4.2). Выводится стандартный диалог SaveFiieDialog сохранения файла, и если пользователь щелкнул на кнопке ОК (или Сохранить), то вызывается процедура Запись (). Если нет, то пользователь отправляется редактировать текст. Процедура Запись() также в точности соответствует процедуре записи текстового файла из предыдущего раздела. Как видно, в процедуре Запись() попытка (Trу) записи заканчивается оператором textBox1.Modified = false. Свойство Modified отслеживает изменения в тестовом поле. Понятно, что сразу после записи в файл следует это свойство перевести в состояние false. На мой взгляд, наибольший интерес представляет организация выхода из программы. Выйти из программы можно либо через пункт меню Выход, либо закрывая программу традиционными методами Windows, т. е. нажатием комбинации клавиш <Alt>+<F4>, кнопки Закрыть или кнопки системного меню (слева вверху)( «обработка события закрытия формы FormClosing). Момент закрытия формы отбиваем с помощью события формы FormClosing, которое происходит во время укрытия формы. Обратите внимание, выход по пункту меню Выход организован не через метод Application.Exit (), а через закрытие формы this .Сlose (). Почему? Потому что метод Application.Exit () не вызывает событие формы FormClosing. Обычно выход из любого редактора (текстового, графического, табличного и т. д.) реализуется по следующему алгоритму. Если пользователь не сделал никаких изменений в редактируемом файле, то выйти из программы. Изменения в текстовом поле регистрируются свойством textBox1.Modified. Если в документе имеются несохраненные изменения (textBox1 .Modified = true), а пользователь хочет выйти из программы, то выводят диалоговое окно (рис. 4.3). |