Текстові файли. Розв’язування задач на зміну текстових файлів. Класи File, StreamReader, StreamWriter
У даній темі наведено приклади рішення найбільш поширених задач, що виникають при обробці текстових файлів на мові C#. Приклади наведені для додатків, створених за шаблоном Console Application. Розв’язок кожної задачі представлений відповідною статичною функцією. За бажанням можна модифікувати продемонстровані статичні функції у функції екземпляру класу.
Для обробки текстових файлів продемонстровано роботу класів File, StreamReader, StreamWriter.
Зміст
- 1. Як визначити, що дані у текстовому файлі закінчились?
- 2. Послідовність дій при читанні даних з файлу. Використання класу StreamReader
- 3. Функція PrintFile(). Вивести вміст текстового файлу на екран. Спосіб 1
- 4. Функція PrintFile2(). Вивести вміст текстового файлу на екран. Спосіб 2
- 5. Функція ReplaceStringInFile(). Заміна рядка у текстовому файлі. Використання можливостей класу File
- 6. Функція RemoveStringFromFile(). Видалення рядка з файлу за його індексом. Приклад
- 7. Функція InsertLineInFile(). Вставка рядка у файл в заданій позиції
- 8. Функція ConvertLinesFileToList(). Конвертувати рядки файлу в список List<string>
- 9. Функція AddArrayLinesInFile(). Додавання масиву рядків в кінець файлу
- 10. Функція SwapLinesInFile(). Обмін місцями двох рядків у файлі. Приклад
- 11. Функція ReverseStringsInFile(). Реверсування рядків файлу (перестановка рядків файлу у зворотному порядку)
- 12. Функція SortLineInFileBubble(). Сортування рядків у файлі методом бульбашки. Приклад
- Зв’язані теми
Пошук на інших ресурсах:
1. Як визначити, що дані у текстовому файлі закінчились?
Читання даних з текстового файлу здійснюється з допомогою методу ReadLine(). Метод читає рядок символів з поточного потоку і повертає його у вигляді типу string. Ознакою закінчення рядка є символ ‘\n’ у файловому потоці. Якщо досягнуто кінець файлу, метод ReadLine() повертає значення null. Відповідна перевірка у програмі дозволяє визначити, чи прочитані усі дані з текстового файлу.
⇑
2. Послідовність дій при читанні даних з файлу. Використання класу StreamReader
Щоб прочитати дані з текстового файлу потрібно виконати приблизно таку послідовність дій:
1. Підключити модуль System.IO з допомогою рядка
using System.IO;
2. Створити екземпляр класу StreamReader з допомогою одного з перевантажених конструкторів. Одночасно зі створенням екземпляру відбувається відкриття файлу для читання або запису. Клас StreamReader має декілька конструкторів.
У нижченаведеному прикладі відкривається текстовий файл з іменем “TextFile1.txt”. Файл відкривається для читання (за замовчуванням).
// Відкрити текстовий файл для читання StreamReader fileObj = new StreamReader("TextFile1.txt");
3. З допомогою екземпляру StreamReader здійснити циклічне читання рядків файлу як показано нижче
... // прочитати один рядок string s = fileObj.ReadLine(); while (s != null) // значення null - кінець файлу { // Виконати дії над рядком s // ... // Прочитати наступний рядок s = fileObj.ReadLine(); } ...
4. Закрити файл з допомогою методу Close()
fileObj.Close()
⇑
3. Функція PrintFile(). Вивести вміст текстового файлу на екран. Спосіб 1
Для наочної демонстрації читання інформації з текстового файлу приводиться статична функція PrintFile(), яка виводить вміст текстового файлу на екран. Для читання рядків з файлу функція використовує метод ReadLine() класу StreamReader. Якщо досягнуто кінець файлу, то ReadLine() повертає null.
using System; using static System.Console; // Для роботи з файлами потрібно підключити модуль IO using System.IO; namespace ConsoleApp7 { class Program { // Статична функція, яка виводить вміст файлу на екран. // Функція використовує метод ReadLine() для читання рядка з файлу. // Ім'я файлу задається вхідним параметром. // Якщо файл успішно прочитано, то функція повертає true. static bool PrintFile(string filename) { // 1. Створити екземпляр класу StreamReader. // Клас StreamReader призначений для читання з потоку символьних даних, // використовується для читання інформації з текстових файлів. StreamReader sr; // 2. Відкрити текстовий файл для читання try { // Спроба відкрити файл для читання (за замовчуванням) sr = new StreamReader(filename); } catch (FileNotFoundException e) { // Якщо спроба невдала, то вивести відповідне повідомлення // та завершити роботу функції WriteLine("Error: {0}", e.Message); return false; } // 3. Цикл читання рядків файлу та вивід їх на екран string s; // додаткова змінна WriteLine("The content of file {0}:", filename); s = sr.ReadLine(); // прочитати перший рядок з файлу while (s != null) // кінець файлу - значення null { // Вивести рядки на екран WriteLine(s); // Прочитати наступний рядок s = sr.ReadLine(); } // 4. Закрити файл sr.Close(); // 5. Вихід з успішним результатом return true; } static void Main(string[] args) { // Вивести вміст файлу "TextFile1.txt" на екран PrintFile("TextFile1.txt"); ReadLine(); } } }
⇑
4. Функція PrintFile2(). Вивести вміст текстового файлу на екран. Спосіб 2
Нижче наведено приклад статичної функції PrintFile2(), яка використовує метод ReadToEnd() класу StreamReader для читання рядків з файлу. На відміну від ReadLine(), метод ReadToEnd() читає усі рядки з файлу і записує їх у рядок типу string включно з символами ‘\n’, ‘\r’.
Алгоритм роботи наступний:
- спочатку читаються усі рядки з файлу в один рядок типу string;
- для отриманого рядка викликається функція Split(), яка розбиває рядок на масив рядків. Ознакою розбиття рядків є символ ‘\n’;
- вивести масив рядків на екран.
using System; using static System.Console; // Для роботи з файлами потрібно підключити модуль IO using System.IO; namespace ConsoleApp7 { class Program { // Вивести вміст текстового файлу на екран. // Функція використовує метод ReadToEnd(). static bool PrintFile2(string filename) { // 1. Створити екземпляр класу StreamReader. // Клас StreamReader призначений для читання з потоку символьних даних, // використовується для читання інформації з текстових файлів. StreamReader sr; // 2. Відкрити текстовий файл для читання try { // Спроба відкрити файл для читання (за замовчуванням) sr = new StreamReader(filename); } catch (FileNotFoundException e) { // Якщо спроба невдала, то вивести відповідне повідомлення // та завершити роботу функції WriteLine("Error: {0}", e.Message); return false; } // 3. Прочитати рядки з файлу в один рядок типу string string s = sr.ReadToEnd(); // 4. Конвертувати рядки з файлу в масив типу string[] string[] lines = s.Split('\n'); // символ-розділювач - '\n' // 5. Вивести масив lines на екран for (int i = 0; i < lines.Length; i++) WriteLine("{0}", lines[i]); // 5. Закрити файл sr.Close(); // 6. Вихід з успішним результатом return true; } static void Main(string[] args) { // Вивести вміст файлу "TextFile1.txt" на екран PrintFile2("TextFile1.txt"); Console.ReadLine(); } } }
⇑
5. Функція ReplaceStringInFile(). Заміна рядка у текстовому файлі. Використання можливостей класу File
При операціях з файлами важливо дотримуватись правильної послідовності читання/запису. Якщо спробувати змінювати дані у файлі безпосередньо, то можна допустити багато невидинмих помилок. Тому, для заміни рядка у текстовому файлі рекомендується використати наступний алгоритм:
- зчитати усі рядки з файлу в масив. У прикладі для читання рядків з файлу використовується метод ReadAllLines() статичного класу File. Цей метод повертає масив типу string[];
- здійснити заміну рядка в масиві;
- записати рядки з масиву знову в файл. Для запису використовується метод WriteAllLines() статичного класу File. У метод передається ім’я файлу та масив рядків типу string[], який потрібно записати.
Текст демонстраційного консольного додатку наведено нижче.
using System; using static System.Console; // Для роботи з файлами потрібно підключити модуль IO using System.IO; namespace ConsoleApp7 { class Program { // Функція, що замінює рядок у текстовому файлі. // Параметри: // - filename - ім'я файлу; // - position - позиція, в якій потрібно замінити рядок (нумерується з 0); // - str - рядок заміни. // Функція повертає true, якщо заміна рядка у файлі відбулась успішно. static bool ReplaceStringInFile(string filename, int position, string str) { // 1. Перевірка, чи файл присутній. // Використовується статична функція Exists(). if (!File.Exists(filename)) return false; // 2. Отримати дані з файлу у вигляді масиву рядків. // Для цього використовується метод ReadAllLines(). string[] arrayS = File.ReadAllLines(filename); // 3. Перевірка, чи коректне значення позиції рядка if ((position < 0) || (position >= arrayS.Length)) return false; // 4. Замінити рядок arrayS[position] = str; // 5. Записати масив рядків у файл filename File.WriteAllLines(filename, arrayS); // 6. Повернути результат return true; } static void Main(string[] args) { // Заміна рядка у файлі // 1. Оголосити змінні string str; int pos; // 2. Ввести вхідні дані Console.WriteLine("Enter string:"); str = Console.ReadLine(); Console.WriteLine("Enter position:"); pos = Convert.ToInt32(Console.ReadLine()); // 3. Використання функції ReplaceStringInFile if (ReplaceStringInFile("TextFile1.txt", pos, str)) Console.WriteLine("Ok!"); else Console.WriteLine("Error."); ReadLine(); } } }
⇑
6. Функція RemoveStringFromFile(). Видалення рядка з файлу за його індексом. Приклад
При маніпуляціях з файлами, які змінюють загальну кількість рядків у файлі (вставка, видалення), краще представляти прочитану інформацію у вигляді списків типу List<string>. Це пов’язано з тим, що в списки зручніше вставляти/видаляти елементи в конкретні позиції. Список не потребує виділення додаткових (часто великих) масивів інформації на відміну від масиву.
У даному прикладі продемонстровано використання функції ReadLine() класу StreamReader. При читанні рядка з файлу ця функція видаляє символи ‘\r’, ‘n’, які потребують додаткової обробки.
using System; using static System.Console; // Для роботи з файлами потрібно підключити модуль IO using System.IO; // Для використання списку List<string> потрібно підключити модуль Generic using System.Collections.Generic; namespace ConsoleApp7 { class Program { // Функція, що реалізує видалення рядка з файлу за його індексом. // Параметри: // - filename - ім'я файлу; // - index - позиція рядка, який потрібно видалити (нумерується з 0). // Якщо видалення відбулось успішно, функція повертає true. static bool RemoveLineFromFileByIndex(string filename, int index) { // 1. Оголосити файлову змінну StreamReader sr; // 2. Спроба відкрити файл filename try { // Використати метод OpenText() класу File sr = File.OpenText(filename); } catch(FileNotFoundException e) { // Якщо файл не знайдено, то обробити виключення WriteLine(e.Message); return false; } // 3. Зчитати усі рядки з файлу в список рядків lst List<string> lst = new List<string>(0); // створити пустий список string s; while ((s = sr.ReadLine()) != null) lst.Add(s); // додати рядок в список // 4. Файл більше не потрібен, тому його можна закрити sr.Close(); // 5. Перевірка, чи коректне значення index if ((index < 0) || (index >= lst.Count)) return false; // 6. Видалити рядок зі списку в позиції index lst.RemoveAt(index); // 7. Записати список lst знову у файл. Для цього потрібно // використати можливості класу StreamWriter // Створити екземпляр класу StreamWriter StreamWriter sw = new StreamWriter(filename); // відкрити файл для запису // Запис списку у файл for (int i = 0; i < lst.Count; i++) sw.WriteLine(lst[i]); // 8. Закрити файл sw.Close(); // 9. Повернути результат return true; } static void Main(string[] args) { // Видалення рядка у файлі // 1. Оголосити змінні int index; // 2. Ввести вхідні дані WriteLine("Enter position:"); index = Convert.ToInt32(Console.ReadLine()); // 3. Використання функції RemoveLineFromFileByIndex() if (RemoveLineFromFileByIndex("TextFile1.txt", index)) WriteLine("Ok!"); else WriteLine("Error."); ReadLine(); } } }
⇑
7. Функція InsertLineInFile(). Вставка рядка у файл в заданій позиції
За зразком пункту 6 можна реалізувати вставку рядка у файл в заданій позиції. Рядки у файлі попередньо копіюються в список типу List<string>. Використання списків у подібних задачах полегшує роботу програміста, оскільки списки містять всі необхідні методи вставки, додавання, видалення елементу.
Запропонована функція InsertLineInFile() має одну особливість. Якщо позиція вставки (нумерується з 0) рівна кількості елементів у файлі n, то рядок вставки додається в кінець файлу. Таким чином функція реалізує вставку та додавання рядка у файл.
// Функція, що реалізує вставку рядка у файл в заданій позиції // Параметри: // - filename - ім'я файлу (повне або скорочене); // - pos - позиція вставки; // - str - рядок, що вставляється. // Функція повертає true, якщо вставка успішна. static bool InsertLineInFile(string filename, int position, string str) { // 1. Оголосити файлову змінну StreamReader sr; // 2. Спроба відкрити файл filename try { // Використати конструктор класу StreamReader sr = new StreamReader(filename); } catch (FileNotFoundException e) { // Якщо файл не знайдено, то обробити виключення WriteLine(e.Message); return false; } // 3. Зчитати усі рядки з файлу в список рядків lst List<string> lst = new List<string>(0); // створити пустий список string s; while ((s = sr.ReadLine()) != null) lst.Add(s); // додати рядок в список // 4. Файл більше не потрібен, тому його можна закрити sr.Close(); // 5. Перевірка, чи коректне значення position if ((position < 0) || (position > lst.Count)) return false; // 6. Реалізувати вставку в список // Якщо position рівне кількості рядків у списку lst, то додати рядок // в кінець списку if (position == lst.Count) lst.Add(str); else lst.Insert(position, str); // 7. Записати список знову в файл // 7.1. Створити екземпляр класу StreamWriter StreamWriter sw = new StreamWriter(filename); // 7.2. Цикл запису списку в файл foreach (string ts in lst) sw.WriteLine(ts); // 7.3. Закрити файл sw.Close(); // 8. Повернути результат return true; }
⇑
8. Функція ConvertLinesFileToList(). Конвертувати рядки файлу в список List<string>
В пунктах 6, 7 повторюється код, що утворює список типу List<string> з рядків файлу. Тому, доцільно написати функцію ConvertLinesFileToList(), яка реалізує конвертування рядків файлу в список. Текст функції наступний.
// Функція, що конвертує рядки файлу в список List<string> // Параметри: // - filename - ім'я файлу; // - LS - список рядків, який отримується читанням з файлу. // Якщо конвертування відбулось успішно, функція повертає true. static bool ConvertLinesFileToList(string filename, out List<string> LS) { // 1. Оголосити файлову змінну StreamReader sr; // 2. Відкрити файл try { // Спроба відкрити файл для читання sr = new StreamReader(filename); } catch(FileNotFoundException e) { // Якщо файл не знайдено, то обробити виключення WriteLine(e.Message); LS = null; return false; } // 3. Зчитати рядки файлу в список LS LS = new List<string>(0); string s; // цикл читання рядків з файлу та утворення списку while ((s = sr.ReadLine()) != null) LS.Add(s); // 4. Закрити файл sr.Close(); // 5. Повернути результат return true; }
⇑
9. Функція AddArrayLinesInFile(). Додавання масиву рядків в кінець файлу
У прикладі наведено функцію, яка додає масив рядків в кінець файлу. Дана функція використовує функцію ConvertLinesFileToList(), яка повертає рядки файлу у вигляді списку і описується в пункті 8. Для роботи з файлами використовуються можливості класів StreamReader та StreamWriter.
Алгоритм методу наступний:
- прочитати дані з файлу в список типу List<string>;
- додати до списку масив рядків;
- записати змінений список у файл. Для запису списку використовуються засоби класу StreamWriter.
Програмний код функції AddArrayLinesInFile() наступний.
using static System.Console; // Для роботи з файлами потрібно підключити модуль IO using System.IO; // Для використання списку List<string> потрібно підключити модуль Generic using System.Collections.Generic; ... // Функція, що додає масив рядків в кінець файлу. // Параметри: // - filename - ім'я файлу; // - arrayS - масив рядків, які додаються в кінець файлу. static bool AddArrayLinesInFile(string filename, string[] arrayS) { // 1. Отримати список рядків файлу List<string> lst; // викликати функцію з п.8 if (!ConvertLinesFileToList(filename, out lst)) { return false; } // 2. Додати масив рядків до списку lst foreach (string s in arrayS) lst.Add(s); // 3. Записати список lst в файл // 3.1. Створити екземпляр класу StreamWriter StreamWriter sw = new StreamWriter(filename); // 3.2. Цикл запису списку в файл foreach (string ts in lst) sw.WriteLine(ts); // 3.3. Закрити файл sw.Close(); // 4. Повернути результат return true; }
Використання функції в іншому програмному коді може бути, наприклад, таким.
static void Main(string[] args) { // Додавання масиву рядків в кінець файлу // 1. Масив рядків string[] arrS = { "abcd", "jklmn", "oprst" }; // 2. Використання функції AddArrayLinesInFile() if (AddArrayLinesInFile("TextFile1.txt", arrS)) WriteLine("Ok!"); else WriteLine("Error."); ReadLine(); }
⇑
10. Функція SwapLinesInFile(). Обмін місцями двох рядків у файлі. Приклад
Обмін місцями двох рядків у файлі не змінює загальну кількість рядків. Тому, прочитані рядки з файлу доцільно представити масивом типу string[].
У C# в статичному класі File є корисна функція ReadAllLines(), яка повертає рядки файлу у вигляді масиву string[]. Як і у випадку з функцією ReadLine() класу StreamReader, кожен рядок у функції ReadAllLines() не містить символів ‘\n’ та ‘\r’.
Статичний файл File також містить функцію WriteAllLines(), яка записує рядки типу string[] у файл.
Нижче наведено фрагмент коду, що містить опис функції SwapLinesInFile().
using static System.Console; // Для роботи з файлами потрібно підключити модуль IO using System.IO; using System; ... // Функція, що міняє місцями два рядки у файлі // Параметри: // - filename - ім'я файлу // - pos1, pos2 - позиції рядків, що обмінюються (нумеруються з 0). // Функція повертає true, якщо обмін рядків відбувся успішно. static bool SwapLinesInFile(string filename, int pos1, int pos2) { // 1. Перевірка, чи файл існує if (!File.Exists(filename)) return false; // 2. Зчитати всі рядки з файлу в масив arrayS string[] arrayS = File.ReadAllLines(filename); // 3. Перевірка, чи значення pos1, pos2 коректні if ((pos1 < 0) || (pos1 >= arrayS.Length)) return false; if ((pos2 < 0) || (pos2 >= arrayS.Length)) return false; // 4. Обміняти місцями рядки в масиві arrayS string s = arrayS[pos1]; arrayS[pos1] = arrayS[pos2]; arrayS[pos2] = s; // 5. Записати змінений масив arrayS знову в файл File.WriteAllLines(filename, arrayS); // 6. Повернути результат return true; }
Використання функції SwapLinesInFile() в іншому коді може бути, наприклад, таким
static void Main(string[] args) { // Обмін місцями двох рядків у файлі // 1. Ввести позиції рядків у файлі int pos1, pos2; Write("pos1 = "); pos1 = Int32.Parse(ReadLine()); Write("pos2 = "); pos2 = Int32.Parse(ReadLine()); // 2. Використання функції if (SwapLinesInFile("TextFile1.txt", pos1, pos2)) WriteLine("Ok!"); else WriteLine("Error."); ReadLine(); }
⇑
11. Функція ReverseStringsInFile(). Реверсування рядків файлу (перестановка рядків файлу у зворотному порядку)
Алгоритм функції наступний:
- прочитати рядки файлу в масив типу string[] з допомогою функції File.ReadAllLines();
- з допомогою циклу реверсувати масив рядків;
- записати реверсовані рядки знову в файл.
Текст функції ReverseStringsInFile() наступний
// Для роботи з файлами потрібно підключити модуль IO using System.IO; // Функція, яка змінює порядок рядків у файлі на зворотній. // Функція повертає true, якщо реверсування відбулось успішно static bool ReverseAllLinesInFile(string filename) { // 1. Перевірка, чи файл існує if (!File.Exists(filename)) return false; // 2. Зчитати всі рядки з файлу в масив arrayS string[] arrayS = File.ReadAllLines(filename); string s; // 3. Реверсувати рядки в масиві arrayS for (int i = 0; i < arrayS.Length / 2; i++) { s = arrayS[i]; arrayS[i] = arrayS[arrayS.Length - i - 1]; arrayS[arrayS.Length - i - 1] = s; } // 4. Записати змінений масив arrayS знову в файл File.WriteAllLines(filename, arrayS); // 5. Повернути результат return true; }
Використання функції може бути, наприклад, таким
static void Main(string[] args) { // Реверсування рядків у файлі if (ReverseAllLinesInFile("TextFile1.txt")) WriteLine("Ok!"); else WriteLine("Error."); ReadLine(); }
⇑
12. Функція SortLineInFileBubble(). Сортування рядків у файлі методом бульбашки. Приклад
using static System.Console; // Для роботи з файлами потрібно підключити модуль IO using System.IO; ... // Функція, яка сортує рядки у файлі методом бульбашки. // Функція повертає true, якщо сортування успішне static bool SortAllLinesInFileBubble(string filename) { // 1. Перевірка, чи файл існує if (!File.Exists(filename)) return false; // 2. Зчитати всі рядки з файлу в масив arrayS string[] arrayS = File.ReadAllLines(filename); string s; // 3. Посортувати рядки у масиві arrayS методом бульбашки for (int i = 0; i < arrayS.Length; i++) for (int j = arrayS.Length - 1; j > i; j--) if (arrayS[j - 1].CompareTo(arrayS[j]) > 0) // сортування за зростанням { s = arrayS[j - 1]; arrayS[j - 1] = arrayS[j]; arrayS[j] = s; } // 4. Записати змінений масив arrayS знову в файл File.WriteAllLines(filename, arrayS); // 5. Повернути результат return true; }
Використання функції SortAllLinesInFileBubble() у функції main()
static void Main(string[] args) { // Сортування рядків у файлі if (SortAllLinesInFileBubble("TextFile1.txt")) WriteLine("Ok!"); else WriteLine("Error."); ReadLine(); }
⇑
Зв’язані теми
⇑