Как правила, работа с файлами в большинстве своем заключается в чтении и записи файлов. Подобной функицональностью обладает класс 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.