В FreeBASIC есть 4 возможных пути для выполнения файлового ввода-вывода:
1. Используя встроенные
BASIC команды, как
Open ,
Get,
Put,
и
Close. Этот способ портативен для
всех платформ, поддерживаемых FreeBASIC. Открытые файлы идентифицируются по "файловому
номеру", это специфично для FreeBASIC и не может быть передано в функции,
описанные ниже.
2. Использование функций ввода-вывода потока C как: fopen, fread, ftell, fclose
(смотрите поток ввода-вывода в
Стандартные
функции библиотеки языка С) библиотеки C , на которую FreeBASIC
опирается. Это немного быстрее, и добавляет несколько дополнительных
функций, в отличие от метода выше, а так же портативно. Открытые файлы
идентифицируются по файловым указателям, как и в языке C, но опять же это
уникально только для данного метода. Функция
FileAttr
может использоваться для возврата указателя на поток ввода\вывода из номера
файла как в пункте 1 выше.
3. Использование низкоуровневых функций ввода-вывода языка C как: _open, _read,
_write, _close (смотрите низкоуровневый ввод-вывод в
Стандартные функции библиотеки языка С).
Эти функции должны быть переносимыми, но пока заголовки доступны только для
Win32, так что нет возможности скомпилировать код для любой другой
платформы.
4. Работать непосредственно с ядром ОС (DOS: используя DOS и DPMI INT's , Win32:
используя API вызовы как CreateFile, WriteFile). Это не является
переносимым. Файлы идентифицируют хендлы, специфичные для ядра ОС.
Этот пример показывает, и сравнивает методы 1. и 2. описанные выше, и
сообщает значения, возвращаемые функциями. Он ожидает, 2 аргумента командной
строки, обеспеченных именами 2-х разных файлов с одинаковым размером и
позволяет сравнить производительность чтения (убедитесь, что кэш файла пуст,
прежде чем начать тест):
Пример
Data " File I/O example & test GET vs FREAD | (CL) 2008-10-12 Public Domain "
Data " http://www.freebasic.net/wiki/wikka.php?wakka=ProPgFileIO "
Rem
Rem Компилировать с FB 0.20 или
более новым
Rem
Rem В командную строку
желательно передать 2 файла одинакового большого размера
Rem По умолчанию "BLAH" для
обоих (плохо)
Rem В обоих циклах (Get и FREAD) последнее
чтение не может быть "пустым" ... никаких проблем
#include "crt\stdio.bi" '' В противном
случае "C"-материал не будет работать
Dim As FILE Ptr QQ '' Это
указатель доступа к файлу C-подобный
Dim As UByte Ptr BUF '' Буфер,
используемый для обоих FB и C для чтения
Dim As UInteger FILN '' FB "файловый
номер"
Dim As UInteger AA, BB, CC, DD, EE
Dim As ULongInt II64 '' Мы
стараемся поддерживать файлы >= 4 GiB
Dim As String VGSTEMP, VGSFILE1, VGSFILE2
? : Read VGSTEMP : ? VGSTEMP : Read VGSTEMP : ? VGSTEMP : ?
VGSTEMP=Command$(1) : VGSFILE1="BLAH"
If (VGSTEMP<>"") Then VGSFILE1=VGSTEMP
VGSTEMP=Command$(2) : VGSFILE2=VGSFILE1
If (VGSTEMP<>"") Then VGSFILE2=VGSTEMP
BUF = Allocate(32768) '' 32
KiB - надеюсь, что он не подведет, BUF может быть 0 ...
? : ? "FB - OPEN - GET , """+VGSFILE1+"""": Sleep 1000
FILN = FreeFile : AA=0 : II64=0 '' AA
подсчитывает блоки по 32 KiB уже прочитанные
BB=Open (VGSFILE1 For Binary Access Read As #FILN)
'' Результат 0 все зашибись, <>0 это
плохо
'' "ACCESS READ" должно предотвратить создание
файла, если он не существует
? "OPEN result : " ; BB
If (BB=0) Then '' BB будет
"повторно" для таймера ниже
BB=Cast(UInteger,(Timer*100)) '' Нет UINTEGER TIMER в FB, сделаем
единицу 10 ms
CC=Get (#FILN,,*BUF,32768,DD)
'' CC статус успеха, 0 в порядке, <> 0
плохо
'' DD это количество считанных данных
'' EOF __НЕ__ рассматривать
как ошибку здесь
? "0th GET : ";CC;" ";DD
? "2 bytes read : ";BUF[0];" ";BUF[1]
Do
AA=AA+1 : II64=II64+Cast(ULongInt,DD)
If (DD<32768) Or (CC<>0) Then Exit Do '' выход
из цикла
CC=Get (#FILN,,*BUF,32768,DD)
Loop
EE=Cast(UInteger,(Timer*100))-BB
? "Time : ";(EE+1)*10;" ms"
If (AA>1) Then ? "Last GET : ";CC;" ";DD
? "Got __EXACTLY__ ";II64;" bytes in ";AA;" calls"
Close #FILN
ENDIF
? : ? "C - FOPEN - FREAD , """+VGSFILE2+"""" : Sleep 1000
AA=0 : II64=0 '' AA
подсчитывает блоки по 32 KiB уже прочитанные
QQ=FOPEN(VGSFILE2,"rb")
'' Здесь 0 это плохо , а <>0
хорошо, по отношению к прошлому методу наоборот!
'' Файл не будет создан, если он не существует (хорошо)
'' "rb" чувствителен к регистру и должен быть в
нижнем регистре, StrPtr кажется не надо
? "FOPEN result : " ; QQ
If (QQ<>0) Then
BB=Cast(UInteger,(Timer*100)) '' Нет UINTEGER TIMER в FB, сделаем
единицу 10 ms
DD=FREAD(BUF,1,32768,QQ)
'' Возвращает размер прочитанных
данных, <32768 уперлись в EOF, 0 после EOF, или "-1" на error
? "0th FREAD : ";DD
? "2 bytes read : ";BUF[0];" ";BUF[1]
Do
AA=AA+1
If (DD<=32768) Then II64=II64+Cast(ULongInt,DD)
If (DD<>32768) Then Exit Do '' ERR или EOF
DD=FREAD(BUF,1,32768,QQ)
Loop
EE=Cast(UInteger,(Timer*100))-BB
? "Time : ";(EE+1)*10;" ms"
If (AA>1) Then ? "Last FREAD : ";DD
? "Got __EXACTLY__ ";II64;" bytes in ";AA;" calls"
FCLOSE(QQ)
ENDIF
Deallocate(BUF): Sleep 1000 '' решено
End
См. также