Page 1 of 1

Can there be in Alaska files larger than 4GB

Posted: Sun Jul 28, 2013 1:07 pm
by Eugene Lutsenko
Is it possible to use Alaska convene and modify files (not database) larger than 4GB.
I tried to create a file with a program which is given below, and I did not succeed. So I put it on the 4GB limit:

Code: Select all

PROCEDURE AppSys
// Рабочий стол остается окном приложения
RETURN

******************************************************************
FUNCTION Main()

DC_IconDefault(1000)

**** Определение максимальной длины текстовой переменной
**mTXT = ""
*DO WHILE .T.
*    mTXT = mTXT + REPLICATE("#",1000000)
*ENDDO
* Оказалось текстовая переменная может содержать до 282 млн.символов

CrLf = CHR(13)+CHR(10)   // Конец строки (записи)

y  = 0                   // Позиция (смещение) записи в файле

N_Rec = 100000           // Число признаков
N_Cls = 13000            // Число классов
N_Col = N_Cls+3          // Число полей

IF FILE("Max_DB.txt")
   ERASE("Max_DB.txt")
ENDIF

******** Структура создаваемой базы
aStructure := { { "Kod_pr", "N", 15, 0},;   // 1
                { "Name"  , "C",250, 0} }   // 2
FOR j=1 TO N_Cls
    FieldName = "N"+ALLTRIM(STR(j,15))
    AADD(aStructure, { FieldName, "N", 19, 3 })
NEXT
AADD(aStructure, { "Summa", "N", 19, 0 })
*** Максимальный размер файла: 2^32 = 4Гб

****** Создание пустого файла БД
Lc_buf = ""
Len_x = STRFILE(Lc_buf,"Max_DB.txt")

****** Формирование пустой записи

FOR j=1 TO N_Col
    Lc_buf = Lc_buf + IF(j>1," ","") + REPLICATE("#", aStructure[j,3])+IF(aStructure[j,4]>0,"."+REPLICATE("#", aStructure[j,4]),"")
NEXT
Lc_buf = Lc_buf + CrLf

N_RecMax = 2^32 / LEN(Lc_buf)                    // Расчет максимального числа записей при зазанном числе классов
MsgBox("Число классов="+STR(N_Cls)+CrLf+"Максимальное число признаков="+STR(N_RecMax))
*RETURN NIL

FOR i=1 TO IF(N_Rec<=N_RecMax,N_Rec,N_RecMax)    // Реальное число записей
    Len_x = STRFILE(Lc_buf,"Max_DB.txt",.T.)
NEXT

RETURN NIL
[/size]

Re: Can there be in Alaska files larger than 4GB

Posted: Tue Jul 30, 2013 8:38 am
by Auge_Ohr
YES you can FWRITE() > 4GB

Code: Select all

#include "Fileio.ch"

PROCEDURE Main
LOCAL cFile    := ".\BIGFILE.TXT"
LOCAL nHandle  := 0
LOCAL i        := 1
LOCAL Imax     := 1000000                        // 1GB
LOCAL nGB      := 1
LOCAL cText    := ""
LOCAL nLen     := 0
LOCAL nTimeON  := 0
LOCAL nTimeOFF := 0
LOCAL aFile

   IF PCOUNT() > 0
      // override default 1GB 
      nGB   := VAL( PVALUE(1) )
   ENDIF

   IF FILE(cFile)
      fErase(cFile)
   ENDIF

   nHandle  := FCreate(cFile, FC_NORMAL )
   IF nHandle == -1
      ? "Error beim Erzeugen der Datei:", FError()
   ELSE
      nLen  := 1024*nGB
      cText := Replicate("*", nLen)

      nTimeON   := SECONDS()
      i := 1
      FOR i := 1 TO iMax
         nbyte := FWrite( nHandle, cText, nLen )
      NEXT
      FClose( nHandle )
      nTimeOFF    := SECONDS()

      ? LTrim(STR(nTimeOFF-nTimeON))+" sec."
   ENDIF

   WAIT

RETURN
i "think" it is STRFILE from XbTool which is limited.
p.s. how did you "check" File Size ? Directory() -> PDR 6377

Re: Can there be in Alaska files larger than 4GB

Posted: Tue Jul 30, 2013 10:14 am
by Eugene Lutsenko
Thank you, Auge_Ohr!

Your program works! It turns out that one team of Alaska for the files are limited 4GB and others do not! An interesting situation. Now I can do what I wanted.

Re: Can there be in Alaska files larger than 4GB

Posted: Wed Jul 31, 2013 9:48 pm
by Eugene Lutsenko
That seems to do the basic functions. The size of the text base is almost the same as dbf, and the velocity of the read and write is almost 3 times faster

Code: Select all

#include "Fileio.ch"    // Max_DB

PROCEDURE AppSys
// Рабочий стол остается окном приложения
RETURN

******************************************************************
FUNCTION Main()

LOCAL Getlist := {}, oProgress, oDialog

DC_IconDefault(1000)

**** Опрделение максимальной длины текстовой переменной для строки базы данных
**mTXT = ""
*DO WHILE .T.
*    mTXT = mTXT + REPLICATE("#",1000000)
*ENDDO
* Оказалось текстовая переменная может содержать до 282 млн.символов. Этого более чем достаточно

CrLf = CHR(13)+CHR(10)     // Конец строки (записи)

N_Cls   =  5               // Число классов
N_Rec   = 20               // Число признаков
DB_name = "Max_DB.txt"     // Имя базы данных

N_Col   = N_Cls+3          // Число полей

********** Структура создаваемой базы

aStructure := { { "Kod_pr", "N", 15, 0},;   // 1
                { "Name"  , "C", 15, 0} }   // 2
FOR j=1 TO N_Cls
    FieldName = "N"+ALLTRIM(STR(j,15))
    AADD(aStructure, { FieldName, "N", 19, 2 })
NEXT
AADD(aStructure, { "Summa", "N", 19, 2 })

**************************************
 DC_ASave(aStructure, "_AbsStruct.arx")      // Когда БД создается - записывать структуру, когда открывается - считывать
*aStructure = DC_ARestore("_AbsStruct.arx")

nHandle := FCreate( DB_name, FC_NORMAL )                   // Создание БД (если она была, то все равно создается пустая) ######
*nHandle := FOpen( DB_name, FO_READWRITE )                 // Открытие базы данных ############################################

IF nHandle = -1
   MsgBox("Файл: "+DB_name+" не может быть создан. Ошибка:"+FERROR())
   RETURN NIL
ENDIF

****** Формирование пустой записи
Lc_buf = ""
FOR j=1 TO N_Col
    S = IF(j=2*INT(j/2),"#","X")
    IF aStructure[j,4] = 0
       Lc_buf = Lc_buf + REPLICATE(S, aStructure[j,3])
    ELSE
       Lc_buf = Lc_buf + REPLICATE(S, aStructure[j,3]-aStructure[j,4]-1)+"."+REPLICATE(S, aStructure[j,4])
    ENDIF
NEXT
Lc_buf = Lc_buf + CrLf
Len_LcBuf = LEN(Lc_buf)

LC_DbCreate( DB_name, nHandle, Lc_buf, N_Rec )             // Создание БД.txt, содержащей N_Rec пустых записей ############
DbCreate( "Max_DB", aStructure )                           // Создание пустой БД.dbf

**** Рассет массива начальных позиций полей в строке
PRIVATE aPos[N_Col]
aPos[1] = 1
FOR j=2 TO N_Col
    aPos[j] = aPos[j-1] + aStructure[j-1,3]
NEXT

*** Отображение начальных позиций полей (отладка)
*aM := {}
*FOR j=1 TO N_Col
*    AADD(aM, STR(j)+" "+STR(aPos[j]))
*NEXT
*LB_Warning(aM)

*** Запись поля в БД (корректная) ***********
FOR i=1 TO N_Rec
    FOR j=1 TO N_Col
        IF aStructure[j,4] = 0
           String = STR(i*1000+j,aStructure[j,3])
        ELSE
           String = STR(i*1000+j+0.12,aStructure[j,3],aStructure[j,4])
        ENDIF
        Flag_err = LC_FieldPut( DB_name, nHandle, i, j, String )     // Запись поля в БД (корректная) #####################
        IF Flag_err
           EXIT
        ENDIF
    NEXT
NEXT

*Flag_err = LC_FieldPut( DB_name, nHandle, Pos, String )             // Запись поля в БД (некорректная)

*** Считывание поля в БД (корректная) ***********

*** Формирование БД.dbf (для отладки)
USE Max_DB EXCLUSIVE NEW;ZAP
SELECT Max_DB
DBGOTOP()
FOR j=1 TO N_Rec
    APPEND BLANK
NEXT

FOR i=1 TO N_Rec
    FOR j=1 TO N_Col
        String = LC_FieldGet( DB_name, nHandle, i, j )               // Считывание поля из БД (корректная) ################
        DO CASE
           CASE aStructure[j,2] = "C"
                DBGOTO(i);FIELDPUT(j, String )                       // Для отладки
           CASE aStructure[j,2] = "N"
                DBGOTO(i);FIELDPUT(j, VAL(String) )                  // Для отладки
        ENDCASE
        IF EMPTY(String)
           EXIT
        ENDIF
    NEXT
NEXT

*String   = LC_FieldGet( DB_name, nHandle, Pos )                     // Считывание поля из БД (некорректная)

******* Эксперимент по определеию скорости обращения к базам данных TXT и  DBF

nTimeON := SECONDS()
FOR i=1 TO N_Rec
    FOR j=1 TO N_Col
        String = LC_FieldGet( DB_name, nHandle, i, j )               // Считывание поля из БД (корректная) ################
        Flag_err = LC_FieldPut( DB_name, nHandle, i, j, String )     // Запись поля в БД (корректная) #####################
    NEXT
NEXT
nTimeOFF := SECONDS()
MsgBox("Время исполнения для БД.TXT="+ALLTRIM(STR(nTimeOFF-nTimeON))+" сек.")

nTimeON := SECONDS()
SELECT Max_DB
FOR i=1 TO N_Rec
    FOR j=1 TO N_Col
        DBGOTO(i);Str = FieldGet( j )
        DBGOTO(i);FIELDPUT(j, Str )  
    NEXT
NEXT
nTimeOFF := SECONDS()
MsgBox("Время исполнения для БД.DBF="+ALLTRIM(STR(nTimeOFF-nTimeON))+" сек.")

*** Результат: обращение к на чтение и запись происходит БД.txt почти в 3 раза быстрее, чем к БД.dbf

FClose( nHandle )                                          // Закрытие базы данных #################

******* Повторное открытие базы и запись в нее ********
nHandle := FOpen( DB_name, FO_READWRITE )                  // Открытие базы данных #################
*** Запись поля в БД (корректная) *********************
FOR i=1 TO N_Rec
    FOR j=1 TO N_Col
        IF aStructure[j,4] = 0
           String = STR(999,aStructure[j,3])
        ELSE
           String = STR(999.99,aStructure[j,3],aStructure[j,4])
        ENDIF
        Flag_err = LC_FieldPut( DB_name, nHandle, i, j, String )     // Запись поля в БД (корректная) #####################
        IF Flag_err
           EXIT
        ENDIF
    NEXT
NEXT

RETURN NIL

***********************************************************
******** Создание Max_БД
******** - DB_name    - имя создаваемой БД
******** - nHandle    - идентификатор создаваемой БД
******** - aStructure - структура создаваемой БД
******** - N_Rec      - количество строк (записей)
***********************************************************
FUNCTION LC_DbCreate( DB_name, nHandle, Lc_buf, N_Rec )

Len_LcBuf = LEN(Lc_buf)

nTimeON := SECONDS()

nMax  = N_Rec
Mess = 'Создание файла: '+DB_name
@ 4,5 DCPROGRESS oProgr SIZE 80,1.1 MAXCOUNT nMax COLOR GRA_CLR_CYAN PERCENT EVERY 100
DCREAD GUI TITLE Mess PARENT @oDial FIT EXIT
oDial:show()

nTime = 0

DC_GetProgress(oProgr,0,nMax)
FOR i=1 TO N_Rec           // Реальное число записей
    Len_rec = FWrite( nHandle, Lc_buf, Len_LcBuf )
    IF Len_rec < Len_LcBuf
       MsgBox("Произошла ошибка записи файла: "+DB_name+". Ошибка:"+FERROR())
       RETURN NIL
    ENDIF
    DC_GetProgress(oProgr, ++nTime, nMax)
NEXT
DC_GetProgress(oProgr,nMax,nMax)

*FClose( nHandle )
nTimeOFF := SECONDS()

*MsgBox("Время исполнения="+ALLTRIM(STR(nTimeOFF-nTimeON))+" сек.")
oDial:Destroy()

RETURN NIL

********************************************
******** Запись поля в Max_БД
********************************************
FUNCTION LC_FieldPut( DB_name, nHandle, mRec, mCol, String )

Pos = (mRec-1) * Len_LcBuf + aPos[mCol] - 1

FSEEK(nHandle, Pos, FS_SET)     // Позиционирование начала поля
Len_str = LEN(String)
N_Write = FWrite( nHandle, String, Len_str )

IF N_Write < Len_str
   Mess = 'Ошибка записи поля: [строка=@, колонка=$] в БД: "#"'
   Mess = STRTRAN(Mess, "#", DB_Name)
   Mess = STRTRAN(Mess, "@", ALLTRIM(STR(mRec)))
   Mess = STRTRAN(Mess, "$", ALLTRIM(STR(mCol)))
   MsgBox(Mess)
   RETURN(.T.)
ENDIF

RETURN(.F.)

********************************************
******** Считывание поля из Max_БД
********************************************
FUNCTION LC_FieldGet( DB_name, nHandle, mRec, mCol )

Len_str = aStructure[mCol,3]

Pos = (mRec-1) * Len_LcBuf + aPos[mCol] - 1

FSEEK(nHandle, Pos, FS_SET)     // Позиционирование начала поля
String = SPACE(Len_str)
N_Read = FRead( nHandle, @String, Len_str )

IF N_Read < Len_str
   Mess = 'Ошибка считывания поля: [строка=@, колонка=$] БД: "#"'
   Mess = STRTRAN(Mess, "#", DB_Name)
   Mess = STRTRAN(Mess, "@", ALLTRIM(STR(mRec)))
   Mess = STRTRAN(Mess, "$", ALLTRIM(STR(mCol)))
   MsgBox(Mess)
   RETURN("")
ENDIF

// Пробел в числовом поле рассматривается как "0"
IF aStructure[mCol,2] = "N" .AND. LEN(ALLTRIM(String)) = 0    
   String = "0"
ENDIF

RETURN(String)

* LC_AppendBl( DB_name, aStructure )
* LC_DeleteBl( DB_name )

******** Display a warning message
******** Может выдавать сообщения элементами массива и без ctitle:

*message := {}
*AADD(message,'1-е сообщение')
*AADD(message,'2-е сообщение')
*AADD(message,'3-е сообщение')
*LB_Warning( message )

FUNCTION LB_Warning( message, ctitle )

  LOCAL aMsg := {}
  DEFAULT cTitle TO ''
  IF valtype(message) # 'A'
    aadd(aMsg,message)
  ELSE
    aMsg := message
  ENDIF
  IF LEN(ALLTRIM(cTitle)) > 0
     DC_MsgBox( ,,aMsg,cTitle)
  ELSE
     DC_MsgBox( ,,aMsg,'Универсальная когнитивная аналитическая система "Эйдос-Х++"')
  ENDIF

RETURN NIL
[/size]