Обработка файлов

Предыдущая тема Следующая тема Перейти вниз

Обработка файлов

Сообщение  tux в Ср Авг 20, 2008 7:28 pm

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

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

Open путь_к_файлу For режим [доп_параметр] [тип_доступа] As [#]номер_файла

где:
путь_к_файлу - путь к файлу, с которым будем работать. FreeBASIC позволяет использовать как прямой путь к файлу, так и относительный (относительно дирректории исполняемого файла), при этом может использоваться как прямой слеш, так и обратный. Это связано с тем, что FreeBASIC является межплатформенным языком программирования, поэтому компилятор сам решит когда необходимо использовать какой символ, и, следовательно, не будет необходимости переписывать исходный код.
режим - режим в котором мы открываем файл. FreeBASIC, как и многие языки программирования, поддерживает два основных режима обработки файла: текстовый и двоичный. Подробноней будет рассказано далее.
доп_параметр - необязательный параметр, который используется в зависимости от режима открытия файла. При обработке текстового фалйа, в качестве этого параметра можно указать кодировку файла (ascii, utf8, utf16 или utf32). А при обработке двоичного файла, в качестве параметра можно указать право доступа на файл: Read - только для чтения, или Write - для записи. Если параметр не указан, то будет поддерживаться оба режима.
тип_доступа - также определяет права доступа на файл, если они не указаны ранее.
номер_файла - дескриптор файла, являющийся любым числом. Также в качестве дескриптора можно использовать любую переменную типа integer, в которой будет храниться значение, полученное функцией FreeFile.
После того, как работа с файлом будет закончена, его можно закрыть с помощью функции close, в качестве параметра которой используется дескриптор файла. Если дескриптор не указан, то закрываются все открытые в данный момент файлы. Также при завершении выполнения программы все открытые файлы автоматически закрываюся.

Режимы доступа к файлам
Как было сказано ранее, существует два режима работы с файлом: текстовый и двоичный.
Текстовый в свою очередь делится на режим чтения - Input, Output и Append.
Если вы указали режим Input, то файл будет открыт в режиме только чтения. Если вдруг файл не будет найден по указанной дирректории, то функция Err, вызванная сразу после открытия файла, вернет ненулевое значение. Однако при этом программа не остановит свое выполнение, но при попытке чтения из этого файла будет фозвращаться пустая строка.
В режиме Output файл будет открыт только в режиме записи. Если же до этого по указанной дирректории существовал какой либо файл, то его содержимое очиститься, а если файл не существовал, то он будет создан.
В режиме Append файл будет открыт для добавления в него информации. При этом информация будет добавляться в конец файла и никак не повлияет на ранее записанную в него информацию.
Двоичный режим делится на Binary и Random.
Режим Binary используется для записи или чтения произвольной длинны двоичных данных.
Режим Random аналогичен режиму Binary, но используется для работы с фиксированной длинной данных.

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

Функция Print #
Для начала рассмутрим функцию Print #, ее синтаксис следующий:

Print # номер_файла, [ список_выражений ] [ , | ; ]

где:
номер_файла - это дескриптор файла, о котором упоминалось выше.
список_выражений - одна или несколько переменных, значения которых мы записываем в файл. Если не указанно ни одной переменной и не будет использовани ни один из символов "," или ";", то в файл запишутся только сиволы перехода на новую строку (chr(13) & chr(10)).
Функция Print # аналогична функции Print, с единствееной разницей, что информация выводится не на экран, а в файл, на что указывает символ "#" и дескриптор файла.
Список переменных можно разделять либо запятой, либо точкой с запятой, либо объединять их символом "&" как обычные строковые переменные.
Функция Print # не требует, чтобы переменные были явно текстового типа, и автоматически числовые преобразует в стоку.
Запятая используется для вывода значений в строку, разделенных между собой как бы табуляторами, однако для этого используются пробелы.

Код:
open "str_out.txt" for output as #1
print #1, "hi", 55, chr(65)
close #1

Данный приме выведет в файл строку следующего вида:

hi 55 A

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

Код:
open "str_out.txt" for output as #1
print #1, "hi"; 55; chr(65)
close #1

В файле будет следующая строка:

hi 55A

Но мы тут видим, что перед вторым выводимым значением у нас почемуто пробел. Это вызвано в связи стем, что 55 не является текстовым типом, и компилятор при автоматическом преобразовании перед всеми числовыми значениями добавляет пробел. Можно конечно взять это число в кавычки, но что делать если у нас это число находится в числовой переменной?. Для этого необходимо использовать явное преобразование в строковый тип функцией Str.

Код:
open "str_out.txt" for output as #1
print #1, "hi"; str(55); chr(65)
close #1

Получаем:

hi55A

Что и требовалось.
Вместо точки с запятой можно также использовать знак "&", при этом результат быдет тем же:

Код:
open "str_out.txt" for output as #1
print #1, "hi" & str(55) & chr(65)
close #1

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

Код:
open "str_out.txt" for output as #1
print #1, "hi"; str(55) 'не ставим точку с запятой
print #1, chr(65)
close #1

В результате получим:

hi55
A

Код:
open "str_out.txt" for output as #1
print #1, "hi"; str(55); 'ставим точку с запятой
print #1, chr(65)
close #1

Получаем:

hi55A

Функция Line Input #
С записью в файл вродебы разобрались. Теперь попробуем получить данные из текстового файла. Для этого используется функция Line Input #. Эта фунция может некотрых напугать тем что состоит из двух отдельных слов, но это единая функция (сделано это для поддержки совместимости синтаксиса ранних языков BASIC-а).
Синтаксис ее следующий:

Line Input #номер_файла, строковая_переменная

где:
номер_файла - дескриптор файла.
строковая_переменная - переменная строгового типа, в которую будет записываться полученная информация.
При вызове функции Line Input #, информация будет сфитыватся построчно начиная спревой строки (если только не используются функции смены позиции начала считывания).
Если функция считала последнюю строку файла, то при дальнейшем вызове она будет получать пустую строку.
После открытия файла желательно проверять, не произошла ли при этом ошибка (вдруг файл отсутствует или к нему нет доступа).
Рассмотим работу функции на примере:

Содадим для примера файл в папке с наше программой с названием str_in.txt и впишем для примера в него такую строку:

ya stroka iz faila

Создадим программу следующего вида:

Код:
dim pStr as string 'создаем переменную, в котрорую будем получать данные
open "str_in.txt" for input as #1 'открываем файл, но уже в режиме input
if err<>0 then 'проверяем, нет ли ошибки откртия файла
    print "error, press any key..."
    sleep
end if
line input #1, pStr 'читаем первую строку
print pStr 'выводим на экран прочитанную строку
close #1
sleep

В результате работы программы на экран получим строку из файла.
Соответсвтенно если повторно вызвать функцию line input #, то считалась бы следующая строка, но так как у нас файл всего из одной строки, то получим пустую строку.
Если в файле много строк, то удобней всего считывать их с помощю цикла, но что если количество строк заранее неизвесно, как отследить, когда файл уже кончился? Для этого существует функция EOF, которой в качестве параметра нуден дескриптор файла (без символа "#"), и которая в случае обнаружения конца файла вернет ненулевое значение (-1) в противном случае 0.
Расмотрим пример с использованием цикла с условием while и функции EOF для чтения всего содержимого файла и вывода его на экран.
Для этого добавим в файл неколько строк произвольной информации.

stroka nomer 1
stroka nomer 2
stroka nomer 3
stroka nomer 4
...

И напишем следующую программу:

Код:
dim pStr as string
open "str_in.txt" for input as #1
if err<>0 then
    print "error, press any key..."
    sleep
end if
while EOF(1)=0 'проверяем не достигнут ли конец файла
    line input #1, pStr
    print pStr
wend
print "EndOfFile"
close #1
sleep

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

Функции Put # и Get #
Функция Put # предназначена для записи в файл любой двоично информации, в качестве которой может быть конечно же и текст.
Ситнаксис ее следующий:

Put #номер_файла As Integer, [позиция As LongInt], данные As Any [, количество As Integer]

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

Код:
dim as byte pVar1, pVar2, pVar3 'создаем переменные размером в один байт
open "bin.dat" for binary as #1 'открываем файл в двоичном режиме
if err<>0 then
    print "error, press any key..."
    sleep
end if
'присваиваем значения переменным
pVar1=65
pVar2=66
pVar3=67
'записываем значения переменных в файл
put #1,, pVar1
put #1,, pVar2
put #1,, pVar3
close #1
sleep

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

Get #номер_файла As Integer, [позиция As LongInt], ByRef данные As Any [, [колличество_в_переменную As Integer] [, ByRef колличество_из_файла As UInteger] ]

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

Код:
dim as byte pVar1, pVar2, pVar3
open "bin.dat" for binary as #1
if err<>0 then
    print "error, press any key..."
    sleep
end if
get #1,, pVar1
get #1,, pVar2
get #1,, pVar3
print pVar1
print pVar2
print pVar3
close #1
sleep

Ну а если хотим получить данные из призвольного места, то указываем позицию, с которой начинаем читать:

Код:
dim as byte pVar
open "bin.dat" for binary as #1
if err<>0 then
    print "error, press any key..."
    sleep
end if
get #1,2, pVar
print pVar
close #1
sleep

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

Код:
dim pStr as string
open "bin.dat" for binary as #1
if err<>0 then
    print "error, press any key..."
    sleep
end if
pStr="qwertyuiop"
put #1, 1, pStr 'записываем строку полностью в файл
pStr=space(5) 'заполняем строку 5-ю пробелами
'это необходимо для того, чтобы компилятор знал размер получаемых данных
get #1, 3, pStr 'читаем начиная с третьего байта 5 байт обратно в строку
print pStr
close #1
sleep

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

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


Последний раз редактировалось: tux (Чт Авг 21, 2008 9:04 am), всего редактировалось 3 раз(а)
avatar
tux

Сообщения : 365
Дата регистрации : 2008-04-06
Возраст : 29
Откуда : Сибирь

Посмотреть профиль http://tux.nsk.ru/

Вернуться к началу Перейти вниз

Re: Обработка файлов

Сообщение  tux в Ср Авг 20, 2008 7:29 pm

Вай, пойду спать, завтра наверно допишу, а пока жду критики))
avatar
tux

Сообщения : 365
Дата регистрации : 2008-04-06
Возраст : 29
Откуда : Сибирь

Посмотреть профиль http://tux.nsk.ru/

Вернуться к началу Перейти вниз

Re: Обработка файлов

Сообщение  Eric-S в Чт Авг 21, 2008 7:51 am

Молодца! На большую тему замахнулся.
Тут ещё писать и писать.

Для текстовых файлов нужно рассказать про input# и write#.

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

Номер файла и дескриптор в бэсике, по моему, это одно и тоже.

Номер же желательно получать динамически, в больших проектах из-за этого будет меньше проблем.

Код:

dim str1 as string
dim ff1 as integer
ff1 = freeFile
if open "myfile.txt" for input as#ff1 then
line input #ff1, str1
print str1
close #ff1
end if

Что же касаеться условия, которое я проверяю. Fb разрешает такое и не нужны проверки err.
(читал но не применял!)


А реальная критика может быть только про грамотность и оформление. Но это не критично.



freeFile
Функция возвращает первый свободный номер файла.

К дескрипторам в языках c и подобных отношения не имеет. Там под дескриптором понимаеться указатель на структуру описывающую работу с файлом.

Eric-S

Сообщения : 738
Дата регистрации : 2008-08-06
Возраст : 34
Откуда : Россия, Санкт-Петербург

Посмотреть профиль http://eric50.narod.ru

Вернуться к началу Перейти вниз

Re: Обработка файлов

Сообщение  tux в Чт Авг 21, 2008 8:16 am

Ну пока столь подробно я думаю на всех тонкостях заострять внимание не стоит, тк это все же для начинающих, и без этого много че надо сказать, ну а со временем канешн будет это все редактироваться да дополняться.

Ну а насчет грамотности согласен, у мня трояк по руссому был((
avatar
tux

Сообщения : 365
Дата регистрации : 2008-04-06
Возраст : 29
Откуда : Сибирь

Посмотреть профиль http://tux.nsk.ru/

Вернуться к началу Перейти вниз

Re: Обработка файлов

Сообщение  Eric-S в Вт Сен 30, 2008 5:06 am

Хочу предложить две функции. Первая
file_putcontent - создаёт или перезаписывает файл указанными данными.
file_getcontent - считывает всё содержимое файла.

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

Можно например работать с ascii текстами или двоичными данными.

Данные передаються в переменной типа string, что кажеться мне самым удобным вариантом.

Unicode не поддерживаеться.

Код:


' записать содержимое файла
sub FILE_PutContent( byVal file_name as string, byRef dat as string )
dim ff1 as integer = FreeFile

' пробное открытие и очистка содержимого
if open( file_name for output as #ff1) = 0 then
close #ff1

' открываем для записи
if open( file_name for binary Access write lock read as #ff1) = 0 then
put #ff1, 1, dat
close #ff1
end if
end if
end sub


' получить содержимое файла
function FILE_GetContent( byVal file_name as string ) as string
dim r as string
dim ff1 as integer = FreeFile
' открываем и читаем файл
if open( file_name for binary Access Read lock write as #ff1) = 0 then
r = String( lof(ff1), 0)
get #ff1, 1, r
close #ff1
end if
return r
end function

Eric-S

Сообщения : 738
Дата регистрации : 2008-08-06
Возраст : 34
Откуда : Россия, Санкт-Петербург

Посмотреть профиль http://eric50.narod.ru

Вернуться к началу Перейти вниз

Re: Обработка файлов

Сообщение  Спонсируемый контент


Спонсируемый контент


Вернуться к началу Перейти вниз

Предыдущая тема Следующая тема Вернуться к началу


 
Права доступа к этому форуму:
Вы не можете отвечать на сообщения