Запись в файл
Начнем с рассмотрения команды, часто встречающейся при работе с файловыми потоками:
Dim myFileStream As New FileStream("MyFile.txt". FileMode.OpenOrCreate, FileAccess.Write)
Как видно из приведенного фрагмента, эта версия конструктора FileStream получает имя файла (заданное по отношению к текущему каталогу, если не указано полное имя) и два параметра, значения которых относятся к перечисляемым типам FileMode и FileAccess соответственно. Таким образом, в нашем примере конструктор Fi1eStream либо создает файл с именем MyFile.txt в текущем каталоге, либо открывает его, если файл с таким именем уже существует. В любом случае программа сможет записывать данные в файл. Часто встречаются и другие конструкторы класса Fi leStream:
Допустимыми значениями перечисляемого типа FileAccesS являются Read, Write и ReadWri te. Основные значения перечисляемого типа Fi I eMode перечислены в табл. 9.9. Учтите, что некоторые из них требуют особых привилегий для операций с файлами.
Таблица 9.9. Значения перечисляемого типа FileMode
Значение |
Описание | ||||
Append | Открыть существующий файл (или создать несуществующий). Указатель текущей позиции перемещается в конец файла для записи. Используется совместно с FileAccess.Write | ||||
Create | Создать новый файл. Внимание — существующий файл автоматически стирается! | ||||
CreateNew | Создать новый файл. Отличается от Create тем, что для существующего файла инициируется исключение IOException | ||||
Open | Открыть существующий файл. Если файл не существует, инициируется исключение IOException. Используется совместно с FileIOPermissionAccess.Read | ||||
OpenOrCreate | Открыть или создать файл | ||||
Truncate | Открыть существующий файл, удалить текущее содержимое | ||||
Объекты FHeStream также возвращаются следующими методами классов File и FHelnfo: File.Create, File.Open, File.OpenRead, File.OpenWrite, FHeInfo.Create, FHelnfo.Open, FHelnfo.OpenRead.
Хотя файловые потоки поддерживают произвольный доступ методом Seek, базовый класс-FileStream ориентирован исключительно на операции с байтами, поэтому его возможности ограничиваются простой записью байта или массива байтов методами WriteByte и Write. Приведенный ниже фрагмент создает файл, показанный на рис. 9.2:
Option Strict On Imports System.IO
Module Modulel
Sub Main()
Dim i As Integer
Dim theBytes(255) As Byte
For i = 0 To 255
theBytes(i) = CByte(i)
Next
Dim myFileStream As FileStream
Try
myFileStream = New FileStream("C:\foo",
Fi1eMode.OpenOrCreate. FileAccess.Write)
myFlleStream.Write(theBytes, 0. 256) Finally
If Not (myFileStream Is Nothing) Then
myFileStream.Close()
End Try
DisplayAFile("C:\foo")
End Sub
End Module
Рис. 9.2. Запись двоичных данных в файл
После выполнения этого фрагмента записанные данные можно прочитать методом Read, а также воспользоваться методом Seek для перехода к произвольной позиции в файле. Впрочем, как это всегда бывает при работе с неструктурированными потоками байтов, вам придется самостоятельно преобразовать двоичные данные в более полезный формат. В результате сейчас трудно найти более содержательный пример, чем простой вывод записанных чисел процедурой, приведенной ниже:
Sub ReadDataBack()
Dim myFileStream As Stream.i As Integer Try
myFileStream = New FileStream("C:\foo",
FileMode.Open. FileAccess.Read)
For i = 0 To 255
Console.Write(myFileStream.ReadByte) Next
Catch e As Exception MsgBox(e.Message)
Finally
If Not (myFileStream Is Nothing) Then
myFileStream.Close()
End Try
End Sub
Метод Length базового класса Stream всегда позволяет прочитать нужное количество байтов в цикле независимо от структуры файла. Например, следующая процедура читает файл по одному байту.
Обнаруженные исключения просто передаются вызывающей стороне; вероятно, в реальной программе следовало бы определить новый класс исключения:
Sub DisplayAFile(ByVal theFileName As String)
Dim theFile As FileStream
Dim i As Long Try
theFile = New FileStream(theFileName.
Fi1eMode.Open,Fi1eAccess.Read)
For i = 0 To (theFile.Length - 1)
' Вычесть 1. поскольку отсчет начинается с 0
Consolе.Write(theFiIe.ReadByte) Next
Catch Throw Finally
If Not (theFile Is Nothing) Then theFile.Close()
End Try
End Sub
Если файл имеет небольшие размеры и легко помещается в памяти, воспользуйтесь одним вызовом Read и прочитайте весь файл в байтовый массив нужного размера. Такая операция выполняется значительно быстрее.
Другой распространенный вариант посимвольного чтения основан на том, что метод ReadByte в конце потока возвращает -1. Основной цикл выглядит примерно так:
Dim i As Integer i = theFile.ReadByte
Do Until i =-1
Console.Write(i)
i = theFile.ReadByte Loop
Чтение/запись файла на уровне отдельных байтов используется не так уж часто; в основном это необходимо при выполнении низкоуровневых операций. При операциях более высокого уровня часто используется стандартный прием — неструктурированный файловый поток передается конструктору потока, обладающего более широкими возможностями. Этот принцип называется многоуровневой организацией потоков. Например, неструктурированный файловый поток можно передать потоку, автоматически распознающему текст. Разные способы многоуровневой организации потоков описаны в нескольких ближайших разделах. Но прежде, чем переходить к этим разделам, просмотрите табл. 9.10 — в ней перечислены основные методы и свойства базового класса FileStream. В дальнейшем мы будем использовать эти методы, хотя базовый файловый поток будет скрыт потоками более высоких уровней.
Таблица 9.10. Основные члены класса RleStream
Метод/свойство |
Описание |
||
Handle (свойство) |
Файловый манипулятор операционной системы для файла, инкапсулированного в объекте FileStream. Свойство доступно для чтения |
||
Length (свойство) |
Размер потока в байтах. Свойство доступно для чтения |
||
Name (свойство) |
Уточненное имя, переданное конструктору FileStream |
||
Position (свойство) |
Текущая позиция для операций чтения или записи в потоке (нумерация позиций начинается с нуля). Свойство доступно для чтения и записи |
||
Close |
Закрывает поток и освобождает все связанные с ним ресурсы |
||
Flush |
Пересылает все данные из буфера в устройство. Автоматически вызывается при вызове Close |
||
Lock(ByVal position As Long, ByVal length As Long) |
Блокирует доступ ко всему файлу или его части со стороны других процессов (нумерация позиций начинается с нуля) |
||
Read(ByVal array() As Byte, ByVal offset As Integer, ByVal count As Integer) |
Читает заданное количество байтов в массив из файлового потока начиная с заданной позиции |
||
ReadByte |
Читает один байт из файла и перемещает указатель текущей позиции на один байт вперед |
||
Seek(ByVal offset As Long, ByVal origin As SeekOrigin) |
Устанавливает указатель текущей позиции в потоке в заданное положение |
||
Unlock(ByVal position As Long, ByVal length As Long) |
Снимает блокировку с ранее заблокированной части файла (нумерация позиций начинается с нуля) |
||
Write(ByVal array() As Byte, ByVal offset As Integer, ByVal count As Integer) |
Записывает заданное количество байт из массива в файловый поток начиная с заданной позиции |
||
WriteByte |
Записывает байт в текущую позицию файлового потока |
||