Классы TextWriter и StreamWriter
Абстрактный класс TextWriter содержит методы, позволяющие производить запись символов в байтовый поток (файл). Основные методы приведены в таблице 10.2.
Таблица 10.2
Методы класса TextWriter
Название |
Описание |
Close() |
Закрывает файл, освобождает связанные с ним ресурсы |
Write() |
Осуществляет запись данных в текстовый поток. Метод позволяет принимать в качестве параметра данные, представленные в разных форматах (целые или вещественные числа, символы или массивы символов, строки, логические переменные) |
WriteLine() |
Записывает в текстовый поток данные, за которыми следует признак конца строки |
Класс StreamWriter является классом-наследником класса TextWriter и реализует методы класса-предка.
Конструктор StreamWriter(<ИмяФайла>) создает текстовый поток для записи данных в заданный файл. Отметим, что имя файла может быть задано с указанием пути либо без него. Если файл существует, он будет перезаписан, в противном случае создается новый файл.
Рассмотрим использованием описанных методов на простом примере: вывести значения одномерного массива в файл. Напишем метод WriteToFile(), реализующий вывод элементов массива в заданный файл. Исходя из условия задачи, метод будет принимать в качестве параметров, во-первых, имя заданного файла FileName, во-вторых, одномерный массив MyArray.
static void WriteToFile(string FileName, int[] MyArray)
{
using (StreamWriter OutputFile = new StreamWriter(FileName))
{
foreach (int element in MyArray)
OutputFile.Write("{0} ", element);
}
}
Здесь мы создаем экземпляр класса StreamWriter с именем OutputFile для заданного файла, в цикле foreach последовательно просматриваем все элементы заданного массива и записываем их в файл с помощью метода Write().
Основная программа включает в себя описание массива с инициализацией и вызов метода WriteToFile().
static void Main(string[] args)
{
int[] MyArray = {1, 22, 13, -4, 5, 16, 27, 18, -9};
WriteToFile("output.txt", MyArray);
}
Отметим, что в рассмотренном примере значения одномерного целочисленного массива MyArray будут записаны в файл через пробел. Имя файла задано без указания пути к файлу, поэтому, чтобы просмотреть результаты работы программы, необходимо открыть файл “output.txt”, который находится в каталоге “…\bin\debug\” текущего решения.
Классы Stream и FileStream
Класс Stream является абстрактным базовым классом всех потоков. При работе с потоком допустимы три основные операции:
чтение из потока – перенос информации из потока в структуру данных, такую как массив байтов;
запись в поток – передача данных из структуры данных в поток;
поиск, включающий в себя отправку запросов и изменение текущей позиции внутри потока.
Некоторые свойства и методы класса Stream приведены в таблице 10.3.
Таблица 10.3
Свойства и методы класса Stream
Название |
Вид |
Описание |
CanRead |
неизменяемое свойство |
Показывает, можно ли ввести данные из потока |
CanWrite |
неизменяемое свойство |
Показывает, можно ли записать данные в поток |
CanSeek |
неизменяемое свойство |
Показывает, поддерживает ли поток произвольный доступ к данным, при котором можно задать текущее положение в потоке |
Close() |
экземплярный метод |
Закрывает текущий поток и освобождает все связанные с ним ресурсы |
Flush() |
экземплярный метод |
Записывает данные из буфера в связанный с потоком источник данных (файл) и очищает буфер |
Length |
неизменяемое свойство |
Возвращает длину потока в байтах |
Position |
изменяемое свойство |
Возвращает либо задает текущее положение в потоке |
Read() |
экземплярный метод |
Считывает последовательность байтов определенной длины из потока и записывает их в одномерный массив байт. Возвращает количество прочитанных байтов либо ноль, если достигнут конец потока |
ReadByte() |
экземплярный метод |
Возвращает целочисленное представление следующего байта из потока либо –1, если достигнут конец потока |
ReadTimeOut |
изменяемое свойство |
Возвращает или задает продолжительность времени ожидания в миллисекундах в процессе чтения данных из потока |
Seek() |
экземплярный метод |
Перемещает указатель текущего положения в потоке на заданную позицию |
Write() |
экземплярный метод |
Записывает последовательность байт определенной длины в массив, начиная с указанного индекса, и перемещает указатель в потоке на количество записанных байт |
WriteByte() |
экземплярный метод |
Записывает один байт в поток и перемещает указатель в потоке на один байт |
WriteTimeOut |
изменяемое свойство |
Возвращает или задает продолжительность времени ожидания в миллисекундах в процессе записи данных в поток |
Ввод/вывод, организованный на уровне байтов, называется байтовым потоком. Для создания байтового потока служит класс FileStream, являющийся классом-наследником класса Stream и реализующий рассмотренные выше методы и свойства. Конструктор класса перегружен и имеет несколько вариантов реализации, мы рассмотрим только одну из них. FileStream(<ИмяФайла>,<Режим>,<ТипДоступа>)- создает экземпляр класса FileStream, связывает его с заданным файлом и открывает файл в заданном режиме с заданным типом доступа. Поясним, что любой файл можно открывать в различных режимах. При этом режим открытия файла задается одним из константных значений перечисления FileMode:
Append – указывает, что операционная система (ОС) должна открыть существующий файл для записи, при этом текущий указатель положения в файле устанавливается в конец файла. Если файл не существует, создает новый файл;
Create – указывает, что ОС должна создать новый файл. Если в каталоге уже существует файл с заданным именем, он будет переписан;
CreateNew – указывает, что ОС должна создать новый файл. Если в каталоге уже существует файл с заданным именем, генерируется исключение IOException;
Open – указывает, что ОС должна открыть существующий файл. Если файл с заданным именем не существует, генерируется исключение FileNotFoudException;
OpenOrCreate – указывает, что ОС должна открыть файл с заданным именем, если он существует, либо создать файл с заданным именем в противном случае;
Truncate – указывает, что ОС должна открыть существующий файл. После открытия он должен быть обрезан до нулевой длины. Файл может быть открыт только для записи.
Кроме режима открытия фала, в конструкторе необходимо указать тип доступа к нему. Этот параметр принимает одно из константных значений перечисления FileAccess:
Read – указывает, что файл открыт только для чтения;
Write – указывает, что файл открыт только для записи;
ReadWrite – указывает, что файл доступен и для чтения и для записи.
Приведем простой пример использования байтовых потоков для записи данных в файл и считывания данных из файла.
try
{
FileStream InputFile = new FileStream("input.txt", FileMode.Create, FileAccess.Write);
for (byte i = 0; i < 100; i++)
InputFile.WriteByte(i);
InputFile.Close();
}
catch
{
Console.WriteLine("Ошибка ввода");
}
Здесь мы создаем файл “input.txt” и открываем его для записи. Далее записываем в него целые числа от 0 до 99. Важно заметить, что при открытии созданного текстового файла вы не увидите числа от 0 до 99. Это связано с тем, что данные записаны в файл на уровне байт, и не преобразованы в символьный формат, удобный для восприятия человеком.
В следующем примере мы открываем созданный файл “input.txt” для чтения и выводим считанные данные на экран.
try
{
FileStream InputFile = new FileStream("input.txt",
FileMode.Open, FileAccess.Read);
int b = InputFile.ReadByte();
while (b != -1)
{
Console.WriteLine(b);
b = InputFile.ReadByte();
}
InputFile.Close();
}
catch
{
Console.WriteLine("Ошибка чтения файла");
}
В результате работы программы на экран будет выведена последовательность чисел от 0 до 99.
Используя метод Seek() для позиционирования указателя текущего положения в файле, можно управлять процессом считывания данных из файла. Синтаксис: Seek(long offset, SeekOrigin origin). Здесь параметр offset задает смещение в байтах относительно точки отсчета положения в потоке. Точка отсчета задается параметром origin и может принимать одно из константных значений перечисления SeekOrigin: Begin – начало файла, Current – текущее положение, End – конец файла.
Следующая модификация рассмотренного выше примера, используя метод Seek(), считывает лишь каждый третий байт из потока.
try
{
FileStream InputFile = new FileStream("input.txt",
FileMode.Open, FileAccess.Read);
int b = InputFile.ReadByte();
while (b != -1)
{
Console.WriteLine(b);
InputFile.Seek(2, SeekOrigin.Current);
b = InputFile.ReadByte();
}
InputFile.Close();
}
catch
{
Console.WriteLine("Ошибка чтения файла");
}
Подчеркнем, что байтовый поток удобно использовать только для решения задач, в которых операции с файлами реализуются программным путем и пользователю не требуется самому изменять содержимое файлов. Если же необходимо считать из файла данные, введенные пользователем и представленные в символьном формате, удобнее пользоваться классами StreamReader и StreamWriter. Напомним, что эти классы, по сути, являются лишь надстройкой над классом Stream, они тоже используют байтовые потоки для чтения данных из файла и записи данных в файл, но при этом выполняют автоматическое преобразование байтового потока в символьный и наоборот (рис. 10.4).
Рис.
10.4.
Байтовый и символьный потоки
