C#. Текстовые файлы. Решение задач на модификацию текстовых файлов. Классы File, StreamReader, StreamWriter

C#. Текстовые файлы. Решение задач на модификацию текстовых файлов. Классы File, StreamReader, StreamWriter

В данной теме приведены примеры решения наиболее распространенных задач, которые возникают при обработке текстовых файлов на языке C#. Примеры приведены для приложений, созданных по шаблону Console Application. Решение каждой задачи представлено соответствующей статической функцией. По желанию можно модифицировать продемонстрированные статические функции в функции экземпляра класса.

Для обработки текстовых файлов продемонстрирована работа классов File, StreamReader, StreamWriter.


Содержание


Поиск на других ресурсах:

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();
}

 


Связанные темы