назад | содержание | вперед

Глава 9. Работа с файлами и организация печати.

При проектировании приложения достаточно часто возникает необходимость работать непосредственно с файлами. Это требуется, например, для добавления, удаления файлов или каталогов (папок), записи данных в файлы или чтения из них как программно, так и в интерактивном режиме. Необходимость работы с файлами возникает также при создании программы инсталляции разработанного приложения на пользовательские компьютеры, чтения данных из файлов при инициализации приложения с использованием файлов настройки, организации вывода файлов на печать. Для этих целей Visual Basic 6 предоставляет полный набор функций, работающих с файлами, папками и устройствами, дающий возможность производить с ними все необходимые действия.

В Visual Basic 6 существует понятие типа файла, который определяется организационной структурой хранения информации в файле и способом доступа к этой информации. Принято выделять следующие типы файлов.

Файлы последовательного доступа. Как правило, это текстовые файлы или аналогичные им. Такие файлы представляют собой последовательность символов. При этом данные могут быть с разделителями или без разделителей, то есть содержание файла может иметь некую структуру. Структурной единицей содержимого в подобных файлах, как правило, является строка. Примерами этих файлов могут служить текстовые файлы и файлы инициализации программ.

Файлы произвольного доступа. Это структурированные файлы, которые содержат информацию в виде записей. Примером могут служить файлы баз данных.

Двоичные (бинарные) файлы. Файлы с побайтным доступом. В принципе, это те же файлы с последовательным доступом, но информация в них не организована в строки. Особенность данных файлов — работа с байтами или блоками байтов. К таким файлам можно отнести выполняемые программы, файлы динамических библиотек, файлы документов Word.

Подобное деление файлов на типы достаточно условно и определяется особенностями организации файлов и доступа к данным в них. Например, файл с последовательным доступом можно открыть и в режиме двоичного доступа. Если этот файл имеет разделители, то для работы с ним придется написать специальную процедуру обработки разделителей и разбора данных, так как двоичный доступ обеспечивает побайтную запись/чтение из файла. Очевидно, что это неудобно. Именно поэтому и введено условное деление файлов на типы в зависимости от формата файла и доступа к данным. Соответственно сгруппированы и функции Visual Basic для записи/чтения данных. Мы рассмотрим работу с каждым из типов файлов, понимая, что такое разделение на типы достаточно условно, но позволяет обеспечить наиболее эффективную обработку данных для каждого типа.

Замечание

Вероятно, более корректным было бы сказать не файл последовательного доступа, а файл, открытый для последовательного доступа, не двоичный файл, а файл, открытый для двоичного доступа. Однако далее будем придерживаться именно такой терминологии, которая указывает тип файла.

Тип файла задает оптимальный набор функций записи и чтения данных из файла. Поэтому при работе с файлами для написания эффективной программы всегда необходимо иметь представление о типах файлов, с которыми будет работать программа, и об организации хранения данных в этих файлах. Это дает возможность обеспечить оптимальный доступ и использовать соответствующие этому доступу функции.

Традиционный подход при работе с файлами

Традиционный подход при работе с файлами остается неизменным практически с самых первых версий Visual Basic и заключается в использовании функций и операторов, обеспечивающих прямой доступ к информации в файлах. Функции и операторы, используемые при работе с файлами, приведены в табл. 9.1. В столбце Тип файла этой таблицы приняты следующие сокращения типов файлов:

В данной главе мы рассмотрим только основные функции и операторы, необходимые для получения навыков работы с файлами.

Таблица 9.1. Функции и операторы для работы с файлами

Функция,оператор

Описание

Тип файла

Open

Открывает файл

П, Пр, Б

Close

Закрывает все файлы

П, Пр, Б

Close #

Закрывает файл по идентификатору (дескриптору)

П, Пр, Б

Reset

Закрывает все открытые файлы, записывает содержимое буферов

П, Пр, Б

Print tt

Записывает данные в файл

П

FileCopy

Копирует файл

П, Пр, Б

EOF

Определяет метку конца файла

П, Пр, Б

FileAttr

Возвращает режим доступа открытого файла

П, Пр, Б

FileDateTime

Возвращает дату и время создания файла

П, Пр, Б

FileLen

Возвращает размер файла в байтах

П, Пр, Б

FreeFile

Возвращает номер свободного идентификатора файла (дескриптора)

П, Пр, Б

GetAttr

Получает атрибуты файла

П, Пр, Б

SetAttr

Устанавливает атрибуты файла

П, Пр, Б

Loc

Возвращает номер текущей позиции в файле

Пр, Б

LOF

Возвращает размер открытого файла в байтах

П, Пр, Б

Seek

Устанавливает на заданную номером позицию или запись в файле

П, Пр, Б

Dir

Возвращает содержимое текущей папки

П, Пр, Б

Kill

Удаляет файл

П, Пр, Б

Lock

Блокирует файл при работе в многопользовательской среде

П, Пр, Б

Unlock

Снимает блокировку файла в многопользовательской среде

П, Пр, Б

Name

Задает (переименовывает) имя файла

П, Пр, Б

Get #

Читает данные из файла

Пр.Б

Input

Читает данные из файла

П, Б

Input #

Читает данные из файла

П

Line Input #

Читает строку из файла

П

Put #

Записывает данные в файл

Пр, Б

Write #

Записывает данные в файл

П


 

Для удобства сгруппируем функции и операторы по выполняемому действию, как это принято в Visual Basic. Такое объединение удобно при выборе функции или оператора для выполнения необходимых действий с файлами (табл. 9.2).

Таблица 9.2. Функции и операторы для работы с файлами по группам

Выполняемое действие

Функции, операторы

Открыть или создать файл

Open

Закрыть файл

Close, Reset

Определение параметров вывода данных

Format, Spc, Tab, Width #

Скопировать файл

FileCopy

Получить информацию о файле

EOF, FileAttr, FlleDateTime, FileLen, FreeFile, GetAttr, Loc, LOF

Организовать управление файлами

Dir, Kill, Lock, Unlock, Name

Прочитать данные из файла

Get #, Input, Input ft, Line Input #

Получить информацию о размере файла

FileLen

Установить атрибуты файла

SetAttr

Найти позиции в файле

Seek

Записать данные в файл

Print tt, Put #, Write ft


 

Открытие файлов

Как было указано выше, работа с каждым из типов файлов имеет свои особенности. Однако есть два действия, общие для всех типов файлов — их открытие и закрытие.

Понятно, что перед тем как записать данные в файл или прочитать данные из файла, необходимо сначала открыть этот файл. Открытие файла выполняется оператором open:

Open pathName For mode [access] [lock] As [#]fileNumber [Len=recLength]

где:

При работе оператора Open создается специальный счетчик номеров (идентификаторов) открытых файлов (в операторе это параметр fileNumber) для однозначного определения файла, с которым программа работает в текущий момент.

Если указанный в операторе open файл не найден по заданному пути или не существует, он будет создан этим оператором для режимов доступа Append, Binary, output или Random. Для режима доступа input новый файл не создается.

Важной особенностью режимов доступа является возможность многократного открытия файла для режимов Binary, input и Random, то есть файл можно открыть несколько раз с разными номерами. Но для режимов доступа Output и Append, используемых для записи данных, это недопустимо.

Если номер открываемого файла специально не контролируется и не задается программой, его можно узнать с помощью функции FreeFile, возвращающей последний свободный номер открываемого файла.

Замечание

При использовании оператора Open необходимо, чтобы режим доступа соответствовал типу открываемого файла.

Закрытие файлов

Закрытие файлов выполняется очень просто. Для этого необходимо использовать оператор close, имеющий следующий синтаксис:

Close [fileNumberLlist]

где fileNumberLlist — список закрываемых файлов, представленных номерами файлов и перечисляемых через запятую: [#fileNumber] [,#fileNumber] . . . [,# fileNumber]. При этом номер файла аналогичен номеру файла в функции open.

Предупреждение

Необходимо иметь в виду, что если список файлов не указан, оператор close закрывает все открытые файлы.

Работа с файлами последовательного доступа

Файлы последовательного доступа — это, как правило, текстовые файлы, то есть последовательности ASCII-символов, организованные в строки. Примером может служить файл инициализации Windows NT (рис. 9.1).

При открытии файлов последовательного доступа возможны три режима доступа:

Рис. 9.1. Пример файла последовательного доступа

Чтение данных

Чтение данных из файла последовательного доступа выполняется с помощью функции Input и операторов Input # и Line Input #. Рассмотрим эти функции и операторы.

Функция Input имеет следующий синтаксис:

Input(number, #fileNumber)

где:

Функция Input считывает из файла заданное количество символов и обычно используется для чтения данных, записанных в файл оператором print #.

Замечание

Следует иметь в виду, что функция input требует знания количества считываемых символов. Поэтому для чтения данных из файла необходимо предварительно вычислить его длину с помощью функции FileLen.

Если в программе требуется прочитать данные из файла, в котором информация в строках имеет структуру с разделителями (в качестве разделителей используются запятые), необходимо применить оператор Input #:

Input #fileNumber, varlist

где:

При работе этого оператора сначала считывается целая строка, а затем подстроки, отделенные разделителями (запятыми), помещаются в соответствующие переменные списка. Для корректной работы оператора строки файла должны иметь заданную структуру с разделителями. Обычно этот оператор используется в паре с оператором записи write #.

Для чтения всего содержимого файла при помощи оператора Input # необходимо организовать циклическое считывание данных из файла, поскольку данные считываются этим оператором по строкам.

Для построчного чтения данных из последовательного файла применяется оператор Line Input #. Синтаксис этого оператора следующий:

Line Input # fileNurnber, varName

где:

Оператор Line Input # посимвольно считывает всю строку данных из файла и помещает ее в строковую переменную. При этом разделителем строк в файле служит стандартный разделитель строк символ возврата каретки CHR(13) или последовательность символов возврата каретки и перевода строки CHR(13) + CHR(10), причем в переменную varName эти разделители не вставляются.

Замечание

Обычно оператор Line Input # используется в паре с оператором Print #.

Для того чтобы прочитать все данные из файла при помощи оператора Line Input #, необходимо организовать цикл чтения данных.

Для изучения функций и операторов, предназначенных для работы с файлами, создадим небольшое приложение. Выполните следующие действия:

1. Создайте новый стандартный проект. Для этого в меню File (Файл) выберите команду New Project (Создать новый) и в окне выбора типа проекта дважды щелкните мышью на значке Standard EXE.

2. Присвойте проекту имя MyFileProject. Используйте для этого окно свойств проекта, которое можно вызвать командой Project1 Properties (Свойства Project1) меню Project (Проект). После переименования проекта эта команда именуется MyFileProject Properties (Свойства MyFileProject).

3. Для выбора файлов потребуются диалоговые окна открытия и сохранения файлов. С помощью диалогового окна Components (Компоненты), вызываемого командой Components меню Project (Проект), подключите к проекту библиотеку Microsoft Common Dialog Control 6.0 и нажмите кнопку ОК.

4. Переименуйте форму проекта, присвоив ей название FormForFile.

5. В свойство caption формы введите заголовок Работаем с файлами.

6. Добавьте в форму элемент управления типа TextBox для ввода/вывода данных и присвойте ему имя txtFile. Придайте текстовому полю достаточно большие размеры, чтобы оно занимало практически все пространство формы. Установите свойство поля Multi-Line в значение True.

7. Добавьте в форму элемент управления CommonDialog, дважды щелкнув мышью кнопку CommonDialog на панели элементов управления.

Совет

Если панель элементов управления отсутствует на экране, для ее отображения в меню View (Вид) выберите команду ToolBox (Панель инструментов).

8. Присвойте созданному объекту типа CommonDialog имя cdCommonDialog.

9. Для фильтрации файлов в свойство Filter объекта cdCommonDialog введите следующий текст: Все файлы (*. *) |*. * | Текстовые файлы (*. txt) \ *. txt \.

10. Добавьте В форму FormForFile кнопку управления типа CommandButton,

дважды щелкнув мышью кнопку CommandButton на панели элементов управления.

11. После появления объекта в форме назовите эту кнопку cbstart и присвойте свойству Caption значение Выполнить. Созданная в форме кнопка cbstart будет служить для выполнения действий по событию кнопки Click.

Созданное тестовое приложение показано на рис. 9.2.

Полученное приложение можно теперь использовать для изучения работы с файлами. Запрограммируем приложение на чтение данных из файла последовательного доступа. Для этого откроем окно редактора кода и введем следующий код:

Dim strFileName As String

Dim strFileContent As String

Dim nFreeFile As Integer

Dim nFileLenght As Integer

Private Sub cbStart_Click()

cdCommonDialog.ShowOpen

strFileName = cdCommonDialog.FileName

nFreeFile = FreeFile

If strFileName <> "" Then

Open strFileName For Input As nFreeFile

nFileLenght = FileLen(strFileName)

strFileContent = Input(nFileLenght, #nFreeFile)

txtFile.Text = strFileContent

Close

End If

End Sub

Рис. 9.2. Вид приложения для изучения функций работы с файлами

Работающее приложение показано на рис. 9.3. В данном случае при нажатии кнопки Выполнить открывается диалоговое окно поиска файла. Путь и имя файла, возвращаемое диалоговым окном, хранятся в переменной strFileName. Найденный файл (он должен быть текстовым) открывается при помощи оператора open для чтения данных. Функция input считывает сразу весь файл в переменную strFileContent, содержимое которой затем помещается в текстовое поле txtFile. После выполнения всех действий файл закрывается оператором close.

Чтобы прочитать данные при помощи оператора Line Input #, необходимо заменить текст кода, расположенный сразу после оператора open, на следующий:

Do While Not EOF(nFreeFile)

Line Input #nFreeFile, strFileContent

txtFile.Text = txtFile.Text + strFileContent +Chr$(13) + Chr$(10) Loop Close

В этом цикле данные из файла построчно считываются в переменную strFileContent и помещаются в текстовое поле txtFile. Цикл работает до достижения конца файла, который контролируется функцией EOF. Применение цикла не требует знания длины файла, что иногда предпочтительнее.

Рис. 9.3. Считывание данных из файла

Для изучения работы оператора input # добавьте в форму еще одно текстовое поле. Назовите его txtNumber И установите свойство поля DataFormat

в значение Number. Текст в приложении после оператора open необходимо заменить на следующий:

Dim nFileContent As Integer

Input #nFreeFile, strFileContent, nFileContent

txtFile.Text = strFileContent

txtNumber.Text = nFileContent

Close

Рис. 9.4. Считывание данных из строк файла в переменные

Работающее приложение показано на рис. 9.4. При этом строки открываемого файла имеют структуру, аналогичную следующей строке:

Это файл для проверки функций, 100

то есть текст и число расположены через запятую.

Переход на заданную позицию в файле

Переход на заданную позицию в файле можно организовать с помощью оператора seek, имеющего следующий синтаксис:

Seek #fileNumber, position

где:

Оператор seek устанавливает указатель на требуемую позицию. Если после этого использовать функции чтения или записи, то действие этих функций будет выполняться начиная с позиции указателя, найденного оператором Seek.

Можно в код приложения MyFileProject непосредственно перед функцией input вставить выражение, задающее позиционирование:

Seek #nFreeFile, 77

nFileLenght = nFileLenght — 76

В этом случае данные из файла будут считаны начиная с 77 по счету символа от начала и до конца файла. При этом необходимо уменьшить число считываемых символов, поскольку считывается весь файл.

Запись данных

Данные в файл последовательного доступа записываются с помощью операторов print # и write #. Оператор write # дополнительно автоматически вставляет в файл разделители, но не дает гибкости при управлении форматированием данных. Как можно было заметить при изучении функций чтения данных, каждая из функций записи работает в паре с определенной функцией чтения. Для оператора print # это функции Input или Line Input #, а для оператора write #t — это Input #.

Совет

Рекомендуется при применении операций записи/чтения данных из файлов использовать именно такие пары функций и операторов записи/чтения.

Рассмотрим оператор print #. Он имеет следующий синтаксис:

Print #fileNumber, [outputlist]

где:

Оператор write ft имеет следующий синтаксис:

Write #fileNumber, [outputlist]

где:

При выполнении записи данных в файл оператор write # после каждой строки автоматически вставляет символ перевода каретки CHR(13) и символ новой строки CHR(10).

Заменим код в нашем приложении MyFileProject на следующий:

Dim strFileName As String

Dim strFileContent As String

Dim nFreeFile As Integer

Private Sub cbStart_Click()

nFreeFile = FreeFile

cdCommonDialog.ShowSave

strFileName = cdCommonDialog.FileName

If strFileName <> "" Then

Open strFileName For Output As nFreeFile

strFileContent = txtFile.Text

Print #nFreeFile, strFileContent

Close

End If

End Sub

В полученном приложении данные, введенные в текстовое поле, будут записываться оператором print # в файл, найденный при помощи диалогового окна сохранения файлов.

Работа с файлами произвольного доступа

Файл с произвольным доступом обладает заранее заданной структурой и состоит из записей. Каждая запись в файле — это некоторая порция данных, которая имеет строго определенный размер и свой конкретный номер в файле. Доступ к данным в файле произвольного доступа осуществляется именно по номеру записи. Данные из файла такого типа читаются и записываются записями. Примерами файла произвольного доступа являются базы данных, всегда имеющие строго определенную структуру.

При открытии файлов произвольного доступа возможен только один режим доступа — Random. Кстати, этот режим является режимом по умолчанию для функции Open.

Используя возможности Visual Basic, можно создать файл произвольного доступа пользовательской, то есть своей собственной структуры. Продемонстрируем это на небольшом примере. С помощью оператора туре объявим тип переменной, имеющей заданную .структуру записи:

Type PhisFace

PhisFaseID As Integer

FIO As String * 50

End Type

В данном примере объявлена структура в виде записи из двух полей. Первым полем является идентификатор, а вторым — фамилия, имя и отчество.

Замечание

Объявление пользовательского типа данных необходимо осуществлять в программном модуле. Для добавления программного модуля в проект следует выполнить команду Add Module (Добавить модуль) из меню Project (Проект) и на вкладке New (Новый) появившегося диалогового окна Add Module выбрать значок с названием Module (Модуль).

Открытие файла произвольного доступа

Файл произвольного доступа открывается несколько иначе, чем файл последовательного доступа. Синтаксис оператора open при этом выглядит следующим образом:

Open pathName [For Random] As fileNumber Len = recLength

где:

При использовании оператора Open для открытия файла произвольного доступа атрибут For не обязателен, так как в Visual Basic 6 этот параметр устанавливается по умолчанию. Как видно из синтаксиса, в отличие от файла с последовательным доступом, при открытии файла с произвольным доступом необходимо обязательно указывать длину записи. При этом, если длина записи не известна, ее можно вычислить с использованием функции Len.

Чтение данных из файла произвольного доступа

Данные из файла произвольного доступа, как правило, считываются записями. Для этого используется оператор Get #, который имеет следующий синтаксис:

Get #fileNumber, [recNumber], varName

где:

Если параметр recNumber в функции Get не указан, считывается текущая запись, на которой позиционирован указатель.

Для позиционирования указателя можно использовать функцию seek. Синтаксис этого оператора такой же, как для файлов последовательного доступа, но имеет другой смысл. Если для последовательных файлов позиционирование выполняется по символам, то для файлов произвольного доступа — по номеру записи:

Seek #fileNumber, position

где:

Запись в файл произвольного доступа

Для записи данных в файл произвольного доступа используется оператор Put #, имеющий следующий синтаксис:

Put #fileNumber, [recNumber], varName

где:

Этот оператор используется только для файлов произвольного доступа и бинарных. Если номер записи не указан, то по умолчанию принимается текущая позиция указателя записи.

Замечание

При использовании оператора Put необходимо иметь в виду, что данные в записи с указанным в операторе номером будут заменены на те, которые мы записываем в файл. Добавление записей выполняется при помощи этого же оператора, но с некоторыми особенностями. Об этом речь пойдет в следующем разделе.

Рассмотрим небольшой пример. Воспользуемся приложением MyFileApp, изменив его следующим образом:

1. Измените наименование кнопки Выполнить на Запись.

2. Добавьте в форму еще одну кнопку управления.

3. Присвойте созданной кнопке наименование cbRead, используя свойство Name.

4. В свойство Caption введите значение Чтение.

5. Добавьте в приложение программный модуль, воспользовавшись командой Add Module (Добавить модуль) из меню Project (Проект).

6. В код модуля введите текст описания пользовательского типа данных:

Type Phis Face

PhisFaseID As Integer

FIO As String * 50

End Type

7. Откройте окно редактора кода и замените находящийся там код на следующий:

Dim ForFileRecords As PhisFace

Dim nRecNo As Integer

Private Sub SaveRecord ()

Open "C:\FilePF.dat" For Random As #1 Len = Len(ForFileRecords)

ForFileRecords.PhisFaseID = txtNumber.Text

ForFileRecords.FIO = txtFile.Text

Put #1, nRecNo, ForFileRecords

nRecNo = nRecNo + 1

Close #1

End Sub

Private Sub ReadRecord ()

Open "C:\FilePF.dat" For Random As #1 Len = Len(ForFileRecords)

Get #1, nRecNo, ForFileRecords

txtNumber.Text = ForFileRecords.PhisFaseID

txtFile.Text = ForFileRecords.FIO

nRecNo = nRecNo + 1

Close #1

End Sub

Private Sub Form Load()

nRecNo = 1

End Sub

Private Sub cbStart_Click()

Call SaveRecord

End Sub

Private Sub cbRead_Click()

Call ReadRecord

End Sub

В тексте этого кода мы объявили переменные ForFileRecords пользовательского типа для описания структуры файла и nRecNo в качестве счетчика записей. Открывая файл с доступом Random и указанием длины записи в соответствии с длиной переменной ForFileRecords, мы создаем файл требуемой структуры.

8. Запустите приложение. При нажатии кнопки Запись выполняется запись содержимого текстовых полей в файл созданной структуры. При нажатии кнопки Чтение эти данные можно прочитать в текстовом поле последовательно по записям, начиная с первой. При этом каждая кнопка вызывает собственную процедуру выполнения действия.

Изменение данных в файле произвольного доступа

Для изменения данных в записях файла (редактирование, добавление, удаление записей) применяется оператор put ft. При его использовании необходимо иметь в виду, что данные в записи будут заменены на те, которые мы передаем в файл. Подчеркнем, что новая запись с данными не создается.

Для добавления записей в файл необходимо указывать номер записи на единицу больший номера последней записи. В этом случае запись будет добавлена в файл, а не изменена. Например:

Put #FileNum, LastRecord + 1, ForFileRecords

Для вычисления текущего номера последней записи LastRecord можно использовать длину записи и размер файла, возвращаемый функцией LOF.

Перейдем к описанию процесса удаления данных из файла произвольного доступа. Существуют два способа. Можно просто очистить соответствующие поля указанных записей, то есть записать в них пустые значения. Однако в этом случае в файле остаются пустые записи. Понятно, что при таком подходе ресурсы (дисковое пространство) используются нерационально.

Для окончательного удаления записей рекомендуется перезаписывать данные в новый файл, пропуская пустые записи. Алгоритм этих действий таков:

1. Создайте новый файл с помощью оператора Open.

2. Перепишите все непустые записи в новый файл, используя оператор Put #.

3. Закройте исходный файл и удалите его при помощи оператора Kill.

4. Переименуйте новый файл в исходный оператором Name.

Получаем тот же самый файл, но уже без пустых записей. При этом экономится пространство диска и время поиска данных в таком файле.

Работа с двоичными файлами

Двоичный файл в корне отличается от файлов последовательного и произвольного доступа. Посмотрите на рис. 9.5. Здесь в качестве примера двоичного файла с помощью редактора Notepad системы Windows открыт выполняемый файл Visual Basic 6.

Рис. 9.5. Пример двоичного файла

Из рисунка видно, что нет смысла просматривать файл в чистом виде, его понимает только специальная программа. Двоичный файл не организован в строки, как файл последовательного доступа, представленный ранее на рис. 9.1. Здесь нельзя выделить строки, записи или иную информационную структуру кроме байтов или блоков байтов.

Двоичный файл открывается только в двух режимах:

Для режима доступа Random к двоичным файлам, в отличие от файлов произвольного доступа, запись не имеет строго заданного размера и обычно вычисляется по соответствующему алгоритму или хранится в записях файла.

Работа с двоичными файлами отличается большей свободой выполнения различных действий, чем с файлами последовательного доступа. В отличие от файлов последовательного доступа, двоичный файл открывается сразу и для чтения, и для записи.

 

назад | содержание | вперед

Hosting uCoz