Как правила, работа с файлами в большинстве своем заключается в чтении и записи файлов. Подобной функицональностью обладает класс FileStream. Он представляет собой поток, связанный с файлом. Рассмотрим его ключевые свойства и методы:
Свойство Length возвращает длину потока в байтах
Свойство Position возвращает текущую позицию в потоке
Метод Read читает данные из файла в массив байтов. Он принимает три параметра:
Read(array As Byte(), offset As Integer, count As Integer) As Integer и возвращает количество успешно считанных байтов
Параметр array представляет массив байтов, в который считываются данные из потока
Параметр offset представляет смещение в байтах в массиве array, начиная с которого в массив array будут помещаться считанные байты
Параметр count - максимальное число байтов, предназначенных для чтения. Если в файле находится меньшее количество байтов, то
все они будут считаны.
Метод Seek(offset As Long, origin As SeekOrigin) As Long устанавливает позицию в потоке со смещением на количество байт, указанных в параметре offset
Метод Write записывает данные из массива байтов в файл. Принимает три параметра:
Write(array As Byte(), offset As Integer, count As Integer)
array представляет массив байтов, откуда будут браться данные для записи в файла
Параметр offset представляет смещение в байтах в массиве array, откуда начинается запись байтов в поток
Параметр count - максимальное число байтов, предназначенных для записи
FileStream предоставляет низкоуровневый доступ к файлам на уровне байтов, поэтому если необходимо выполнить чтение или запись строк в текстовый файл, то массив байтов надо преобразовать в строки с помощью специальных методов. Поэтому для работы с текстовыми файлами лучше использовать другие классы, которые мы далее рассмотрим.
В то же время при работе с различными бинарными файлами, имеющими определенную структуру FileStream может быть очень даже полезен для извлечения определенных порций информации и ее обработки.
Посмотрим на примере считывания-записи в текстовый файл:
Imports System.IO
Module Module1
Sub Main()
Console.WriteLine("Введите строку для записи в файл:")
Dim text As String = Console.ReadLine()
'запись в файл
Using fstream As New FileStream("C:\SomeDir\noname\note.txt", FileMode.OpenOrCreate)
'преобразуем строку в байты
Dim array As Byte() = System.Text.Encoding.Default.GetBytes(text)
'записываем массив байтов в файл
fstream.Write(array, 0, array.Length)
Console.WriteLine("Текст записан в файл")
End Using
'чтение из файла
Using fstream As FileStream = File.OpenRead("C:\SomeDir\noname\note.txt")
'преобразуем строку в байты
Dim array As Byte() = New Byte(fstream.Length) {}
'чтение данных
fstream.Read(array, 0, array.Length)
'декодируем байты в строку
Dim textFromFile As String = System.Text.Encoding.Default.GetString(array)
Console.WriteLine("Текст из файла: {0}", textFromFile)
End Using
Console.ReadLine()
End Sub
End Module
Разберем этот пример. И при чтении, и при записи применяется выражение Using....End Using.
Данная конструкция позволяет создать объект, который реализует интерфейс IDisposable. И при завершении выполнения кода в этом блоке
у данного объекта вызывается метод Dispose, и, таким образом, объект уничтожается. В данном случае
в качестве такого объекта служит переменная fstream.
Общий синтаксис конструкции идентичен объявлению переменной, только вместо оператора Dim идет слово Using, а весь блок ззаканчивается
выражением End Using
Мы могли бы не использовать конструкцию Using, тогда в этом случае нам нужно бы было явным образом закрыть поток с помощью метода Close:
Dim fstream As New FileStream("C:\SomeDir\noname\note.txt", FileMode.OpenOrCreate)
Dim array As Byte() = System.Text.Encoding.Default.GetBytes(text)
fstream.Write(array, 0, array.Length)
fstream.Close()
Объект fstream создается двумя разными способами: через конструктор и через один из статических методов класса File.
Здесь в конструктор передается два параметра: путь к файлу и перечисление FileMode. Данное перечисление указывает на режим доступа к
файлу и может принимать следующие значения:
Append: если файл существует, то текст добавляется в конец файл. Если файла нет, то он создается. Файл открывается только для записи.
Create: создается новый файл. Если такой файл уже существует, то он перезаписывается
CreateNew: создается новый файл. Если такой файл уже существует, то он приложение выбрасывает ошибку
Open: открывает файл. Если файл не существует, выбрасывается исключение
Create: создается новый файл. Если такой файл уже существует, то он перезаписывается
OpenOrCreate: если файл существует, он открывается, если нет - создается новый
Truncate: если файл существует, то он перезаписывается. Файл открывается только для записи.
Статический метод OpenRead класса File открывает файл для чтения и возвращает объект FileStream.
Класса FileStream также имеет ряд перегруженных версий конструктора, которые позволяют задать дополнительные параметры потока. Все эти версии можно посмотреть на msdn.
Когда мы работаем с текстовыми файлами, то при записи и при чтении применяется объект кодировки Encoding.Default из пространства имен System.Text.
В данном случае мы используем два его метода: GetBytes для получения массива байтов из строки и
GetString для преобразования массива байтов в строку.
В итоге введенная нами строка записывается в файл C:\SomeDir\noname\note.txt. Но по сути это не текстовый, а бинарный файл, хотя если мы в него запишем только строку, то сможем в любом текстовом редакторе посмотреть файл в удобочитаемом виде. Но если мы в него запишем случайные байты, то у нас могут возникнуть проблемы с его пониманием. Например:
fstream.WriteByte(13) fstream.WriteByte(103)
Поэтому для работы непосредственно с текстовыми файлами предназначены отдельные классы - StreamReader и StreamWriter.