Шрифт:
Очевидно, когда вы хотите быстро получить дескриптор файла, тип File избавит вас от необходимости ввода нескольких лишних строк. Однако преимущество предварительного создания объекта FileInfo заключается в том, что тогда вы получаете возможность исследовать соответствующий файл с помощью членов абстрактного базового класса FileSystemInfо.
Абстрактный класс Stream
К этому моменту вы уже видели множество способов получения объектов FileStream, StreamReader и StreamWriter, но вам придется еще читать и записывать данные файлов, связанных с этими типами. Чтобы понять, как это делается, нужно ознакомиться с понятием потока. В "мире" ввода-вывода поток представляет порцию данных. Потоки обеспечивают общую возможность взаимодействия с последовательностями байтов, независимо от того, на устройстве какого вида (в файле, сетевом соединении, принтере и т.п.) они хранятся или отображаются.
Абстрактный класс System.IO.Stream определяет ряд членов, обеспечивающих поддержку синхронного и асинхронного взаимодействия с носителем данных (скажем, с файлом или областью памяти). На рис. 16.6 показано несколько потомков типа Stream.
Рис. 16.6. Типы, производные от Stream
Замечание. Следует знать, что понятие потока применимо не только к файлам или области памяти. Без сомнения, библиотеки .NET обеспечивают потоковый доступ к сетям и другим связанным с потоками абстракциям.
Напомним, что потомки stream представляют данные в виде "сырого" потока байтов, поэтому работа с потоками может быть весьма непонятной. Некоторые относящиеся к Stream типы поддерживают поиск – этот термин, по сути, означает процесс получения он изменения текущей позиции в потоке. Чтобы понять функциональные возможности, предлагаемые классом Stream, рассмотрите его базовые члены, описанные в табл. 16.6.
Таблица 16.6. Абстрактные члены Stream
Члены | Описание |
---|---|
CanRead CanSeek CanWrite | Определяет, поддерживает ли текущий поток чтение, поиск и/или запись |
Close | Завершает текущий поток и освобождает все связанные с текущим потоком ресурсы (например, сокеты и дескрипторы файлов) |
Flush | Обновляет связанный источник данных или хранилище в соответствии с текущим состоянием буфера, а затем очищает буфер. Если поток не реализует буфер, этот метод не делает ничего |
Length | Возвращает длину потока в байтах |
Position | Определяет позицию в текущем потоке |
Read ReadByte | Читает последовательность байтов (или один байт) из текущего потока и сдвигает указатель позиции в соответствии со считанным числом байтов |
Seek | Устанавливает указатель в заданную; позицию в текущем потоке |
SetLength | Устанавливает длину текущего потока |
Write WriteByte | Записывает последовательность байтов (или один байт) в текущий поток и сдвигает указатель позиции в соответствии со считанным числом байтов |
Работа с FileStream
Класс FileStream обеспечивает реализацию абстрактных членов Stream в виде, подходящем для файловых потоков. Это довольно примитивный поток – он может читать или записывать только один байт или массив байтов. На самом деле необходимость непосредственного взаимодействия с членами типа FileStream возникает очень редко. Вы чаще будете использовать различные упаковщики потоков, которые упрощают работу с текстовыми данными или типами .NET. Однако для примера давайте поэкспериментируем со средствами синхронного чтения/записи типа FileStream.
Предположим, что мы создали новое консольное приложение FileStreamApp. Нашей целью является запись простого текстового сообщения в новый файл с именем myMessage.dat. Но поскольку FileStream может воздействовать только на отдельные байты, требуется перевести тип System.String в соответствующий массив байтов. К счастью, в пространстве имен System.Text определяется тип Encoding, предлагающий члены, которые выполняют кодирование и декодирование строк и массивов байтов (для подробного описания типа Encoding обратитесь к документации .NET Framework 2.0 SDK).
После выполнения кодирования массив байтов переводится в файл с помощью метода FileStream.Write. Чтобы прочитать байты обратно в память, необходимо переустановить внутренний указатель позиции потока (с помощью свойства Position) и вызвать метод ReadByte. Наконец, массив байтов и декодированная строка выводятся на консоль. Вот полный текст соответствующего метода Main.