Книга: C# 4.0: полное руководство

Символьный ввод-вывод в файл

Символьный ввод-вывод в файл

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

Не следует, однако, забывать, что на уровне операционной системы файл представляет собой набор байтов. И применение класса StreamReader или StreamWriter никак не может этого изменить.

Класс StreamWriter является производным от класса ТехtWriteг, а класс StreamReader — производным от класса TextReader. Следовательно, в классах StreamReader и StreamWriter доступны методы и свойства, определенные в их базовых классах.

Применение класса StreamWriter

Для создания символьного потока вывода достаточно заключить объект класса Stream, например FileStream, в оболочку класса StreamWriter. В классе StreamWriter определено несколько конструкторов. Ниже приведен едва ли не самый распространенный среди них:

StreamWriter(Stream поток)

где поток обозначает имя открытого потока. Этот конструктор генерирует исключение ArgumentException, если поток не открыт для вывода, а также исключение ArgumentNullException, если поток оказывается пустым. После создания объекта класс StreamWriter выполняет автоматическое преобразование символов в байты.

Ниже приведен простой пример сервисной программы ввода с клавиатуры и вывода на диск набранных текстовых строк, сохраняемых в файле test.txt. Набираемый тест вводится до тех пор, пока в нем не встретится строка "стоп". Для символьного вывода в файл в этой программе используется объект класса FileStream, заключенный в оболочку класса StreamWriter.

// Простая сервисная программа ввода с клавиатуры и вывода на диск,
// демонстрирующая применение класса StreamWriter.
using System;
using System.IO;
class KtoD {
  static void Main() {
    string str;
    FileStream fout;
    // Открыть сначала поток файлового ввода-вывода,
    try {
      fout = new FileStream("test.txt", FileMode.Create);
    }
    catch(IOException exc) {
      Console.WriteLine("Ошибка открытия файла:" + exc.Message);
      return ;
    }
    // Заключить поток файлового ввода-вывода
    //в оболочку класса StreamWriter.
    StreamWriter fstr_out = new StreamWriter(fout) ;
    try {
      Console.WriteLine("Введите текст, а по окончании — 'стоп'.");
      do {
        Console.Write (": ");
        str = Console.ReadLine();
        if(str != "стоп") {
          str = str + "rn"; // добавить новую строку
          fstr_out.Write(str);
        }
      } while(str != "стоп");
    } catch(IOException exc) {
      Console.WriteLine("Ошибка ввода-вывода:n" + exc.Message);
    } finally {
      fstr_out.Close();
    }
  }
}

В некоторых случаях файл удобнее открывать средствами самого класса StreamWriter. Для этого служит один из следующих конструкторов:

StreamWriter(string путь)
StreamWriter(string путь, bool append)

где путь — это имя открываемого файла, включая полный путь к нему. Если во второй форме этого конструктора значение параметра append равно true, то выводимые данные присоединяются в конец существующего файла. В противном случае эти данные перезаписывают содержимое указанного файла. Но независимо от формы конструктора файл создается, если он не существует. При появлении ошибок ввода-вывода в обоих случаях генерируется исключение IOException. Кроме того, могут быть сгенерированы и другие исключения.

Ниже приведен вариант представленной ранее сервисной программы ввода с клавиатуры и вывода на диск, измененный таким образом, чтобы открывать выходной файл средствами самого класса StreamWriter.

// Открыть файл средствами класса StreamWriter.
using System;
using System.IO;
class KtoD {
  static void Main() {
    string str;
    StreamWriter fstr_out = null;
    try {
      // Открыть файл, заключенный в оболочку класса StreamWriter.
      fstr_out = new StreamWriter("test.txt");
      Console.WriteLine("Введите текст, а по окончании — 'стоп'.");
      do {
        Console.Write (": ");
        str = Console.ReadLine();
        if(str != "стоп") {
          str = str + "rn"; // добавить новую строку
          fstr_out.Write(str);
        }
      } while(str != "стоп");
    } catch(IOException exc) {
      Console.WriteLine("Ошибка ввода-вывода:n" + exc.Message);
    } finally {
      if(fstr_out != null) fstr_out.Close() ;
    }
  }
}

Применение класса StreamReader

Для создания символьного потока ввода достаточно заключить байтовый поток в оболочку класса StreamReader. В классе StreamReader определено несколько конструкторов. Ниже приведен наиболее часто используемый конструктор:

StreamReader(Stream поток)

где поток обозначает имя открытого потока. Этот конструктор генерирует исключение ArgumentNullException, если поток оказывается пустым, а также исключение ArgumentException, если поток не открыт для ввода. После своего создания объект класса StreamReader выполняет автоматическое преобразование байтов в символы. По завершении ввода из потока типа StreamReader его нужно закрыть. При этом закрывается и базовый поток.

В приведенном ниже примере создается простая сервисная программа ввода с диска и вывода на экран содержимого текстового файла test.txt. Она служит дополнением к представленной ранее сервисной программе ввода с клавиатуры и вывода на диск.

// Простая сервисная программа ввода с диска и вывода на экран,
// демонстрирующая применение класса StreamReader.
using System;
using System.IO;
class DtoS {
  static void Main() {
    FileStream fin;
    string s;
    try {
      fin = new FileStream("test.txt", FileMode.Open);
    }
    catch(IOException exc) {
      Console.WriteLine("Ошибка открытия файла:" + exc.Message);
      return;
    }
    StreamReader fstr_in = new StreamReader(fin);
    try {
      while((s = fstr_in.ReadLine()) != null) {
        Console.WriteLine(s);
      }
    } catch(IOException exc) {
      Console.WriteLine("Ошибка ввода-вывода:n" + exc.Message);
    } finally {
      fstr_in.Close();
    }
  }
}

Обратите внимание на то, как в этой программе определяется конец файла. Когда метод ReadLine() возвращает пустую ссылку, это означает, что достигнут конец файла. Такой способ вполне работоспособен, но в классе StreamReader предоставляется еще одно средство для обнаружения конца потока — EndOfStream. Это доступное для чтения свойство имеет логическое значение true, когда достигается конец потока, в противном случае — логическое значение false. Следовательно, свойство EndOfStream можно использовать для отслеживания конца файла. В качестве примера ниже представлен другой способ организации цикла while для чтения из файла.

while(!fstr_in.EndOfStream) {
  s = fstr_in.ReadLine();
  Console.WriteLine(s);
}

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

Иногда файл проще открыть, используя непосредственно класс StreamReader, аналогично классу StreamWriter. Для этой цели служит следующий конструктор:

StreamReader(string путь)

где путь — это имя открываемого файла, включая полный путь к нему. Указываемый файл должен существовать. В противном случае генерируется исключение FileNotFoundException. Если путь оказывается пустым, то генерируется исключение ArgumentNullException. А если путь содержит пустую строку, то генерируется исключение ArgumentException. Кроме того, могут быть сгенерированы исключения IOException и DirectoryNotFoundException.

Оглавление книги


Генерация: 1.130. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз