Файловый ввод\вывод с FreeBASIC
 

В 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



См. также