Работа с файлами
Наконец настала очередь знакомиться с функциями, способными создавать, читать, редактировать файлы. Сказать по чести я сам не использую встроенные средства для работы с файлами. Мне быстрее и удобнее работать с файлами при помощи моей библиотеки Window9 , либо с помощью API функций Windows.
OPEN
Для создания , открытия файла в FreeBasic есть функция Open. Она имеет как бы один параметр в котором сочетаются несколько параметров с ключевыми словами, которые разделены пробелами. Никаких разделяющих запятых нет.
Синтаксис:
Open( имя файла, For {Input | Output | Append}, As дескриптор )
ИЛИ
ТАК
Open( имя файла, For Binary, Access{Read | Write}, As дескриптор
)
ИЛИ ТАК
Open( имя файла, For Random, Access{Read | Write}, As
дескриптор [размер буфера] )
- имя файла с полным путем к нему
- режим работы с файлом
- текстовый
- Input
- Encoding
- ASCII
- UTF-8
- UTF-16
- UTF-32
- Encoding
- Output
- Encoding
- ASCII
- UTF-8
- UTF-16
- UTF-32
- Encoding
- Append
- Encoding
- ASCII
- UTF-8
- UTF-16
- UTF-32
- Encoding
- Input
- двоичный
- Binary
- Access
- Read
- Write
- Access
- Random
- Access
- Read
- Write
- Access
- Binary
- текстовый
- Дескриптор файла
- Размер буфера для записи (длина)
Вот такое дерево я соорудил, но давайте разберем каждую запись.
Первый пункт определяет имя файла часто с расширением, который нужно открыть или создать. Если файл находится не в общей папке с программой, то нужно указывать и путь до него.
Второй пункт режим работы с файлом. Может быть текстовый и двоичный. В
текстовом режиме нужно указать тип открытия или создания:
- Input - только для чтения (если файл не будет найден, функция вернет код ошибки с помощью функции Err.)
- Output - только для записи(если файла не существует, то создаст его. Если файл есть, то перезапишет)
- Append - для записи в конец файла (предыдущая записанная информация в файле сохраняется
Дополнительно можно указать режим кодировки с помощью ключевого слова Encoding и строки с нужной кодировкой для открытия файла: ASCII или Unicode. По умолчанию кодировка ASCII
В двоичном режиме нужно указывать одно из ключевых слов:
- Binary - Запись или чтение двоичных стандартных типов данных (Byte, Integer и пр.).
- Random - Запись или чтение двоичных данных нестандартных типов данных
Дополнительно в двоичном режиме можно указать доступ к файлу с помощью ключевого слова Access и:
- Read - только чтение
- Write - только запись
Если ничего не указывать, то по умолчанию и то и другое.
Дескриптор файла необходим для функций позволяющих считывать информацию из
файла или записывать ее в файл. Представьте себе, если бы дескриптор каким
нибудь образом был не нужен. Тогда при открытии нескольких файлов, как бы вы
определяли в какой файл нужно записать , а из которого прочитать?
Дескриптор - это идентификатор файла, как у человека есть фамилия ,
имя и отчество.
Записывается дескриптор с помощью символа # и цифры (либо
переменной, олицетворяющей эту цифру)
Последний параметр размер буфера для чтения или записи. По умолчанию буфер равен 128 байт.
Во всей записи функции Open не обошлось без вспомогательных команд For и
As.
Далее примеры записи команды Open
Пример_1:
'Открытие текстового файла с именем 1.txt для записи Open "1.txt" For Output As #1 Close #1
Пример_2:
'Открытие текстового файла с именем 1.txt для чтения Open "1.txt" For Input As #1 Close #1
Пример_3:
'Открытие текстового файла с именем 1.txt для чтения в юникоде Open "1.txt" For Input Encoding "UTF-8" As #1 Close #1
Пример_4:
'Открытие двоичного файла с именем 1.txt для чтения и записи Open "1.txt" For Binary As #1 Close #1
Пример_5:
'Открытие двоичного файла с именем 1.txt только для чтения Open "1.txt" For Binary Access Read As #1 Close #1
Пример_6:
'Открытие двоичного файла с именем 1.txt только для чтения с нестандартным типом данных Open "1.txt" For Random Access Read As #1 len=200 Close #1
В обязательном порядке следует закрывать открытые дескрипторы с помощью функции Close. Если вы работаете только с одним файлом, то номер дескриптора после функции Close указывать не обязательно.
FreeFile
При работе с большим кол-вом файлов, все время нужно помнить, какие номера дескрипторов задействованы. При создании или открытии нового файла, нужно точно знать: свободен ли определенный номер дескриптора. Чтобы не держать эту информацию в голове и не рыться лишний раз в своем исходном тексте, можно просто и легко получать действительно свободный дескриптор с помощью функции FreeFile. Пример:
Dim D As Integer = Freefile Open "File1" For Input As #D Close
Print # и Input #
Для записи в файл или чтения из него, который открыт в текстовом режиме,
применяются команды Print # (запись) и Input # (чтение). Помните я говорил о
многофункциональности функций Print и Input ? При работе с файлами эти функции
используются практически так же как в консоли. Есть конечно отличия и давайте их
разберем.
Функция Print при работе с файлами, дополнительно имеет один
параметр в начале. Этим параметром является дескриптор файла, тот же что и для
функции OPEN. В остальном никаких отличий нет, если конечно принять во внимание
что информация выводится не в консоль, а в файл.
Пример_1:
Open "1.txt" For Output As #1 Print #1, "FreeBasic" Close #1
Пример_2:
Open "1.txt" For Output As #1 Print #1,"" 'пустая строка Print #1, 10;20;9999 Print #1, 10,20,9999 Close #1
Откройте файл , который мы создали и записали. В нем вы можете увидеть
примерно следующее:
пустая строка
10 20
9999
10
20 9999
Наверно
ожидалось, что вторая записываемая строка будет сочетать в себе слитное
содержание всех трех цифр (10209999) . Однако они разделены пробелом. Связано
это с тем, что функция Print при преобразовании числа, автоматом впереди
добавляет пробел (в консоли кстати так же). Если нужна запись вместе , то
преобразовать придется вручную с помощью строковых функций (Str или с помощью
оператора &).
Функция Input при работе с файлами, вместо строковой подсказки для пользователя в первом параметре имеет дескриптор файла.
Пример:
Dim s As String 'записываем в файл Open "1.txt" For Output As #1 Print #1, "FreeBasic" Close #1 'читаем из файла Open "1.txt" For Input As #1 Input #1,S ? s Sleep Close #1
Line Input #
Представьте себе, что нам нужно прочитать строку содержащую запятые. Тогда
как вы понимаете, функция Input не годится, поскольку она разделит строку на
аргументы. И в итоге вместо "Казнить нельзя, помиловать" , получит только первые
два слова.
Тут нас выручит знакомая нам консольная функция Line Input .
Перед тем как запускать пример ниже, нужно сохранить файл с исходным кодом в
кодировке Unicode. Для этого в редакторе FbEdit в меню файл->сохранить как
ставим галочку напротив Save As Unicode
Dim s As Wstring * 128="Казнить нельзя, помиловать" 'записываем в файл Open "1.txt" For Output Encoding "utf-8" As #1 Print #1, s Close #1 'читаем из файла Open "1.txt" For Input Encoding "utf-8" As #1 Line Input #1,s ? s Sleep Close
В результате вы увидели в консоли русские символы. Это один из способов
вывода русских символов в консоль, но я предпочитаю лучше преобразовывать с
помощью Api функций, хотя бы потому, что большинство Api функций работает со
стандартом ASCII. Хотя для некоторых есть прототипы для Unicode.
Print # Using
Так же можно применять для записи в файл функцию с расширенным форматированием Print # Using. Использование ее точно такое же как в консоли:
Open "1.txt" For Output As #1 Print #1, Using "This file is called '&'"; "1.txt" Close #1
WRITE #
Функция write # работает точно так же, как в консоли. В результате примера ниже, в файле будут выведены числа через запятую.
Open "1.txt" For Output As #1 Write #1,10,20,30 Close
Get # и Put #
При работе с двоичными файлами скорость несомненно выше, чем при работе в текстовом режиме. Для двоичного режима уже бесполезно использовать функции текстового режима Print, Input и пр. Конечно можно было разработчикам дополнить возможностями текстовые функции, но тогда скорость считывания и записи была бы на порядок ниже. Возможно именно поэтому для таких целей были определены другие функции Get # (для чтения) и Put # (для записи).
Синтаксис этих функций одинаков:
Get дескриптор, позиция в файле, буфер , [размер буфера]
Put дескриптор, позиция в файле, буфер , [размер буфера]
- Дескриптор , тот же, что и для функции OPEN
- Позиция в файле с которой начинать читать или записывать. Если не указывать, то берется та позиция, на которой остановилось чтение или запись.
- Может быть любой буфер памяти: переменная, массив, и пр.
- Размер буфера (необязательный параметр), особенно полезен для буфера, выделенного вручную, например с помощью функции Allocate.
Пример_1:
Dim a As Integer = 565656 'Записываем в файл Open "1.txt" For Binary As #1 Put #1, , a Close #1 'Читаем из файла Open "1.txt" For Binary As #1 Get #1,,a ? a Sleep Close #1
Пример_2
Dim a(5) As Integer = {1,2,3,4,5,6} 'Записываем в файл Open "1.txt" For Binary As #1 Put #1, , a(0),3 Close #1 'Очищаем массив Erase (a) 'Читаем из файла Open "1.txt" For Binary As #1 Get #1,,a(0),3 For b As Integer = 0 To 5 ? a(b) Next Sleep Close #1
В примере_2 я создал массив с 6 ячейками и заполнил их цифрами от 1
до 6. Далее записал в файл не весь массив, а только первые три ячейки. Дальше
очистил массив. Потом прочитал файл, заполняя половину массива. И вывел в цикле
в консоль содержимое всего массива.
Пример_3:
'Открытие двоичного файла с именем 1.txt с нестандартным типом данных Type AA a As Byte b As Integer End Type Dim F As AA= Type(100,599999) Open "1.txt" For Random As #1 Len = Sizeof(AA) Put #1,,F Close Open "1.txt" For Random As #1 Len = Sizeof(AA) Dim G As AA Get #1,,G Close ? G.a ? G.b Sleep
SEEK
Мы узнали как записывать информацию в начало файла. Но бывает, что нужно записать что-то в середину. Для того, чтобы это сделать есть функция перемещения указателя в файле для чтения и(или) записи. Функция как вы поняли носит название Seek. Она же кстати может получать текущее значение указателя в файле.
Синтаксис:
Для получения указателя:
текущее значение указателя = SEEK( дескриптор)
Для установки указателя:
SEEK дескриптор , новое значение указателя
Пример:
Dim i As Integer = 1111, f As Integer = Freefile Open "1.txt" For Binary As #f ? Seek(f)'указатель на 1 позиции Put #f,,i ? Seek(f)'указатель на 5 позиции Seek f,3 ' ставим указатель на 2 позицию Put #f,,i Close #f Open "1.txt" For Binary As #f Get #f,,i ? i Close #f Sleep
Конечно в данном примере легко можно было обойтись без Seek для того, чтобы устанавливать указатель, поскольку функции Get и Put это и сами умеют, но для текстового режима функция Seek будет очень полезна:
Open "1.txt" For Output As #1 Print #1, "FreeBasic" ? Seek(1) Close #1 Sleep
Наверно заметили, что букв в слове FreeBasic 9 , а указатель
находится на 12 позиции. Все правильно, ведь в строке дополнительно еще
помещаются спецсимволы 13 и 10 ( возврат каретки и перенос строки )
LOC
Так же для получения указателя последнего положения при чтении или записи можно использовать функцию LOC. У нее всего один параметр: номер дескриптора файла.
Пример:
Open "1.txt" For Binary As #1 Dim t As Integer = 36474 Put #1, , t ? Loc(1) Close Sleep
LOF
Для получения длины файла на диске можно использовать функцию LOF, имеющую один параметр: номер дескриптора файла
Пример:
Open "1.txt" For Binary As #1 Dim t As Integer = 36474 Put #1, , t Close Open "1.txt" For Binary As #1 ? Lof(1) Close Sleep
EOF
Если функция EOF возвращает ненулевое значение (-1), то это скажет нам , что указатель находится в конце файла. Это часто бывает полезным , например при прочтении всего файла.
Dim s As String 'записываем в файл Open "1.txt" For Output As #1 Print #1, "FreeBasic" Print #1, "Assembler" Close #1 'читаем из файла Open "1.txt" For Input As #1 While Eof(1)=0 Input #1,S ? s Wend Sleep Close #1
LOCK и UNLOCK
Когда несколько программ могут одновременно обращаться к одному файлу, это может вызвать ошибки. Для безопасного чтения и записи в таких случаях лучше применять функции блокировки определенных участков файла. В итоге например нам надо записать что-то в начале файла, середина и конец файла нас не интересует. Мы попросту блокируем нужный участок файла и пишем , остальные участки файла остаются доступными для других программ. Для блокировки и разблокировки можно использовать функции Lock и UnLock. У функций одинаковые параметры:
Lock дескриптор , диапазон
UnLock дескриптор , диапазон
Пример:
Dim i As Integer = 33333 Open "1.txt" For Binary As #1 Put #1,,i Put #1,5,i Close #1 Open "1.txt" For Binary As #1 Lock #1, 1 To 4 Put #1,1,i Unlock #1, 1 To 4 Close #1
Все примеры, что мы рассмотрели были по возможности кратки, но почти все
были построены не совсем корректно. Представьте себе, что файла для открытия не
оказалось, либо система блокирует создание файла, тогда все остальные функции
завязанные на этом дескрипторе могут вызвать серьезные аварии в программе. Для
того, чтобы избежать подобного, нужно всегда после работы функции OPEN проверять
функцией ERR на возможность ошибок. Если произошла какая-то ошибка, тогда
как минимум не использовать функции привязанные к этому дескриптору. Функция ERR
возвращает 0 если ошибок не было, в остальных случаях возвращает код ошибки.
Пример:
Open "1.txt" For Output As #1 If Err = 0 Then Print #1 ,"FreeBasic" Close Endif
Мы рассмотрели достаточно много, но кое-что еще осталось, например удаление, копирование, перемещение файла. Это мы оставим на следующую статью.
Всего доброго!
содержание | назад | вперед