
- •Тема 1 Колекції Структури даних
- •Неузагальнені колекції
- •Деякі інтерфейси неузагальнених колекцій
- •Деякі класи неузагальнених колекцій
- •Узагальнені колекції
- •Тема 2 Файловий ввід-вивід Організація файлового вводу-виводу
- •Байтовий ввід-вивід у файл
- •Двійковий ввід-вивід у файл
- •Символьний ввід-вивід у файл
- •Організація роботи із файлами даних стандарту xml
- •Простір імен System.Xml
- •Класи XmlNode та XmlLinkedNode
- •Клас XmlDeclaration
- •Класи XmlComment та XmlAttribute
- •Клас XmlElement
- •Клас XmlDocument
- •Приклад
- •Тема 3 Делегати та події Клас delegate
- •Делегати в якості параметрів
- •Анонімні методи та узагальнені делегати System.Action, System.Func
- •Комбіновані делегати та шаблон «спостерігач»
- •Події: створення та обробка
Символьний ввід-вивід у файл
Для вводу-виводу у текстовий файл призначені класи символьних потоків StreamWriter та StreamReader. При цьому слід розуміти, що на рівні операційної системи будь-який текстовий файл є набором байтів. Тобто для реалізації вводу-виводу у текстовий файл може бути використаний клас байтового потоку. Але перевагою класів StreamWriter та StreamReader є те, що ці класи є оболочками деякого базового байтового потоку, який керує вводом-виводом символьних даних, і у цих класах реалізовано автоматичне приведення базового байтового потоку у символьний і навпаки.
Для зчитування із текстового файлу використовується клас потоку StreamReader. Цей клас є похідним від абстрактного класу TextReader, від якого він успадковує більшу частину своєї функціональності. Нижче наводяться найбільш важливі елементи цього класу.
Елемент класу TextReader |
Призначення |
public virtual int Peek(); |
Повертає ціле число, яке представляє наступний символ, читання якого потрібно здійснити, або значення -1, якщо доступних символів немає. |
public virtual int Read(); |
Зчитує дані із вхідного потока. |
public virtual int ReadBlock(char[] buffer, int index, int count); |
Зчитує із потоку count символів, починаючи із позиції index, та записує їх у buffer. |
public virtual string ReadLine(); |
Зчитує рядок із потоку. Порожній рядок (null) означає кінець файлу. |
public virtual string ReadToEnd(); |
Зчитує всі символи до кінця потоку, починаючи із поточної позиції, та повертає зчитані дані як один рядок. |
public override void Close(); |
Закриває файл та звільняє пов’язані із ним ресурси. При цьому буфер автоматично очищується. |
Із власних елементів класу StreamReader відмітимо наступні:
Елемент класу StreamReader |
Призначення |
public StreamReader(Stream stream); |
Цей варіант конструктора дозволяє створити символьний потік, ставши оболочкою для базового байтового потоку stream. Як правило, у якості цього параметра використовують об’єкт класу FileStream. При цьому базовий потік stream має бути створений у режимі доступу для читання. Якщо параметр stream виявляється порожнім, те генерується виняткова ситуація ArgumentNullException. А якщо потік, заданий параметром stream, не був відкритий для зчитування даних, то генерується виняткова ситуація ArgumentException. |
public StreamReader(string path); |
Цей варіант конструктора дозволяє створити символьний потік для читання, вказавши абсолютний або відносний шлях до файлу. При цьому неявно створюється базовий байтовий потік для читання. |
public virtual Stream BaseStream { get; } |
Повертає базовий потік, з яким працює об’єкт класу StreamReader. |
public bool EndOfStream { get; } |
Повертає значення true, якщо показчик у потоці знаходиться у кінці цього потоку, інакше − false. |
public override void Close(); |
Закриває потік. При цьому закривається і базовий потік. |
Особливості роботи із класом символьного потоку StreamReader розглянемо на прикладі програмної реалізації наступної задачі.
Нехай задано текстовий файл. Визначити рядок найбільшої довжини. |
class Program { public static void maxLengthLine(string FileName) { // пробуємо створити символьний потік для зчитування try { StreamReader f = new StreamReader(FileName); // довжина максимального рядка int maxLength = -1; // рядок максимальної довжини string longestS = null; // зчитування рядків із текстового файлу можна організувати, наприклад, так: while (!f.EndOfStream) { // зчитуємо черговий рядок із файлу string s = f.ReadLine(); // дивимось, чи зчитаний рядок не є довшим за найдовший зчитаний до цього if (s.Length > maxLength) { maxLength = s.Length; longestS = s; } } // дивимось, можливо, текстовий файл був порожнім if (longestS != null) Console.WriteLine(longestS); else Console.WriteLine("Файл порожній."); // закриваємо символьний потік для зчитування f.Close(); } catch (Exception e) { Console.WriteLine("Помилка: {0}", e.Message); } catch (FileNotFoundException e) { Console.WriteLine(e.Message); Console.WriteLine("Не правильно вказано ім'я файлу."); } } } |
Для запису у текстовий файл використовується клас потоку StreamWriter. Цей клас є похідним від абстрактного класу TextWriter, від якого він успадковує більшу частину своєї функціональності. Нижче наводяться найбільш важливі елементи цього класу.
Елемент класу TextWriter |
Призначення |
public virtual void Close() |
Закриває файл та звільняє пов’язані із ним ресурси. При цьому буфер автоматично очищується. |
public virtual void Flush() |
Очищає всі буфери для поточного файлу та записує накопичені в них дані у файл. Сам файл при цьому не закривається. |
public virtual string NewLine { get; set; } |
Повертає або задає ознаку кінця рядка. |
Write |
Ряд методів, які дозволяють записати у символьний потік фрагменту тексту. |
WriteLine |
Ряд методів, які дозволяють записати у символьний потік фрагменту тексту із ознакою кінця рядка. |
Із власних елементів класу StreamWriter відмітимо наступні:
Елемент класу StreamWriter |
Призначення |
public StreamWriter(Stream stream); |
Цей варіант конструктора дозволяє створити символьний потік, ставши оболочкою для базового байтового потоку stream. Як правило, у якості цього параметра використовують об’єкт класу FileStream. При цьому базовий потік stream має бути створений у режимі доступу для запису. Якщо параметр stream виявляється порожнім, те генерується виняткова ситуація ArgumentNullException. А якщо потік, заданий параметром stream, не був відкритий для зчитування даних, то генерується виняткова ситуація ArgumentException. |
public StreamWriter(string path); |
Цей варіант конструктора дозволяє створити символьний потік для запису, вказавши абсолютний або відносний шлях до файлу. При цьому неявно створюється базовий байтовий потік для запису. |
public StreamWriter(string path, bool append); |
Цей варіант конструктора дає можливість відкрити існуючий текстовий файл для дописування у нього даних. При цьому, якщо файл існує та значення параметра append дорівнює false, то файл перезаписується.Якщо файл існує та значення параметра append дорівнює true, то у файл додаються дані. Інакше − створюється новий файл. |
public virtual Stream BaseStream { get; } |
Повертає базовий потік, з яким працює об’єкт класу StreamWriter. |
public override void Close(); |
Закриває потік. При цьому закривається і базовий потік. |
Особливості роботи із класом символьного потоку StreamReader розглянемо на прикладі програмної реалізації наступної задачі.
Нехай задано текстовий файл, у якому слова розділені пробілами. Перенести у новий файл всі рядки, які містять задане слово. |
class Program { public static void MoveAllLines(string word, string fromFile, string toFile) { // пробуємо створити символьні потоки для зчитування та запису для відповідних файлів try { StreamReader sr = new StreamReader(fromFile); StreamWriter sw = new StreamWriter(toFile); // організовуємо цикл для зчитування рядків із заданого текстового файлу while (!sr.EndOfStream) { // зчитуємо черговий рядок із файлу string s = sr.ReadLine(); // дивимось, чи зчитаний рядок містить задане слово if (s.IndexOf(word)>=0) { // записуємо зчитаний рядок у новий файл sw.WriteLine(s); } } // закриваємо відповідні символьні потоки sr.Close(); sw.Close(); } catch (FileNotFoundException e) { Console.WriteLine(e.Message); Console.WriteLine("Не правильно вказано ім'я файлу."); } catch (Exception e) { Console.WriteLine("Помилка: {0}", e.Message); } } } |
Часто текстові файли використовуються для збереження матриць. Тому на завершення цього параграфу наведемо приклад реалізації класу IntMatrix цілочислових прямокутних матриць, в якому наводиться приклад реалізації зчитування прямокутної цілочислової матриці із текстового файлу (метод LoadFromFile) та збереження прямокутної цілочислової матриці у текстовому файлі (метод SaveToFile).
class IntMatrix { // кількість рядків матриці int RowCount; // кількість стовпців матриці int ColCount; // масив елементів матриці int[,] array; // метод зчитування наступного цілого числа у заданому символьному потоці зчитування int ReadNextInt(StreamReader sr) { // рядкове представлення цілого числа string tmp = null; // змінна, у яку буде зчитуватися наступний символ із потоку char c; // проопускаємо всі пробіли перед черговим числом do { c = (char)sr.Read(); } while (c == ' '); // поки не досягнуто наступного пробілу і не досягнуто кінець рядка \r\n while (c != ' ' & c != '\r' & c != '\n') { // додаємо зчитану цифру до поточного рядкового представлення числа tmp += c; // зчитуємо наступну цифру c = (char)sr.Read(); } // на основі сформованого рядкового представлення числа повертаємо це число if(tmp!=null) return int.Parse(tmp); return 0; } public void LoadFromFile(string fileName) { // пробуємо створити символьний потік для зчитування try { StreamReader f = new StreamReader(fileName); // зчитуємо кількість рядків матриці RowCount = ReadNextInt(f); // зчитуємо кількість стовпців матриці ColCount = ReadNextInt(f); // переводимо показчик у потоці на новий рядок f.ReadLine(); array = new int[RowCount,ColCount]; // зчитуємо елементи матриці у двовимірний масив array for (int i = 0; i < RowCount; i++) { for (int j = 0; j < ColCount; j++) array[i, j] = ReadNextInt(f); f.ReadLine(); } // закриваємо символьний потік f.Close(); } catch (Exception e) { Console.WriteLine("Помилка: {0}", e.Message); } } public void SaveToFile(string fileName) { // пробуємо створити символьний потік для запису try { StreamWriter f = new StreamWriter(fileName); // записуємо у перший рядок текстового файлу через пробіл розмірність матриці f.WriteLine("{0} {1}",RowCount,ColCount); // записуємо елементи матриці у текстовий файл for (int i = 0; i < RowCount; i++) { for (int j = 0; j < ColCount; j++) // записуємо у файл через пробіл елементи i-го рядка матриці f.Write(" {0}", array[i, j]); // переходимо на новий рядок у файлі f.WriteLine(); } // закриваємо символьний потік f.Close(); } catch (Exception e) { Console.WriteLine("Помилка: {0}", e.Message); } } public void Display() { for (int i = 0; i < RowCount; i++) { for (int j = 0; j < ColCount; j++) Console.Write(" {0}", array[i, j]); Console.WriteLine(); } } } |