Page 1 of 2

Closing the database opened with FOpen

Posted: Fri Aug 23, 2013 6:06 am
by Eugene Lutsenko
When you open the database with a USE, then there is no problem then close them all by CLOSE ALL and not have to keep track of which have been opened, and which are not. Is it possible to immediately close all the same base, opened with Fopen not listing them nHandle?

Re: Closing the database opened with FOpen

Posted: Fri Aug 23, 2013 8:46 am
by Auge_Ohr
what about QUIT ;)

i did not understand what you try to do using "low-level" Function ?
if you want to use "ASCII Files" as Database why not use SDFDBE as DATA-Komponente ?

Re: Closing the database opened with FOpen

Posted: Sat Aug 24, 2013 4:55 am
by Eugene Lutsenko
QUIT - this is what we need, but unfortunately it has one side effect - the output of the program. Seriously, if there was a similar QUIT without exiting the program, it would really be what you need. I made a few functions to work with databases on the basis of low-level functions and working with databases larger than 2GB and more fields in 1600. Tried in field experiments to 100,000 and 100,000 records, it turns out the base 254Gb.

Code: Select all

**************************************************************************************************
*** Эксперимент по созданию и заполнению базы данных сверхбольшой размерности собственного формата
*** БД создается похожей на Abs, Prc1, Prc2, Inf1-Inf7, т.к. это нужно в первую очередь для них
*** (С) Е.В.Луценко, 01.08.2013
**************************************************************************************************

FUNCTION M_a_i_n()        // Это ПРИМЕРЫ обращения к функциям работы с текстовой базой данных

LOCAL Getlist := {}, oProgress, oDialog

DC_IconDefault(1000)

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

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

N_Cls   = 1000             // Число классов
N_Rec   = 1000             // Число признаков
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")

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

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

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

***** Формирование пустой записи
CrLf   = CHR(13)+CHR(10)     // Конец строки (записи)
Lc_buf = ""
FOR j=1 TO N_Col
    S = IF(j=2*INT(j/2),"#","X")        // Для отладки
*   S = " "                             // Для работы
    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 )           // Закрытие текстовой базы данных ######################################

RETURN NIL

***********************************************************
******** Создание Max_БД
******** - DB_name    - имя создаваемой БД
******** - nHandle    - идентификатор создаваемой БД
******** - Lc_buf     - пустая запись (строка) базы данных
******** - 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)
[/size]

There is only one problem. When you close these bases, there is an impression that they are still open, at least for a while.

What is: "SDFDBE as DATA-Komponente"

Re: Closing the database opened with FOpen

Posted: Sat Aug 24, 2013 5:27 am
by rdonnay
Here's what I would do:

Code: Select all


STATIC saFiles[0]

FUNCTION Main()

LOCAL nHandle1, nHandle2

nHandle1 := OpenFile( 'MyDataFile1.xxx' )
nHandle2 := OpenFile( 'MyDataFile2.xxx' )

CloseFiles()

RETURN nil


FUNCTION OpenFile( cFileName )

LOCAL nHandle

nHandle := FOpen( cFileName )

AAdd( saFiles, nHandle )

RETURN nHandle

* -------------

FUNCTION CloseFiles()

LOCAL i

FOR i := 1 TO Len(saFiles)
   FClose( saFiles[i] )
NEXT

ASize( saFiles, 0 )

RETURN nil

Re: Closing the database opened with FOpen

Posted: Sat Aug 24, 2013 9:02 am
by Eugene Lutsenko
Yes, like I'm doing...

Re: Closing the database opened with FOpen

Posted: Sat Aug 24, 2013 9:25 am
by Auge_Ohr
Eugene Lutsenko wrote:What is: "SDFDBE as DATA-Komponente"
look into Xbase++ Help file : SDFDBE (DATA-Komponente)

Re: Closing the database opened with FOpen

Posted: Sat Aug 24, 2013 11:06 am
by Eugene Lutsenko
Auge_Ohr wrote:
Eugene Lutsenko wrote:What is: "SDFDBE as DATA-Komponente"
look into Xbase++ Help file : SDFDBE (DATA-Komponente)
Read a little and I had the distinct impression that I invented, and even have made ​​the bike, but it is worse than it was coined to me. But to make sure that it is necessary to conduct experiments. If you like it - I will use it.



Began to try. Like the way done. When I made ​​my version also thought to an external file with a structure of sdf, but then decided not to do it, because in my program, there is always information about the structure of the file and I just wrote down the structure of the array to disk as arx.

While it turns to open the SDF base only if the mechanism of SDF is set by default: DbeSetDefault ("SDFDBE"). And I would like to specify the mechanism of CDF when opening the database: USE TestSDF VIA SDFDBE like the example in the documentation. But this method fails. It is necessary to simultaneously use the SDF and the usual DBF files.

Then still be testing at the time of treatment.

Code: Select all

#include 'dmlb.ch'
#include 'SdfDbe.ch'

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

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

LOCAL Getlist := {}, oProgress, oDialog

DC_IconDefault(1000)

DbeSetDefault( "SDFDBE" )


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

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

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

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 })
AADD(aStructure, { "Sredn", "N", 19, 2 })
AADD(aStructure, { "Disp" , "N", 19, 2 })

**************************************

DbCreate( "TestSDF", aStructure, "SDFDBE" )   // Создать БД с использованием механизма SDF 
DbCreate( "TestDBF", aStructure, "DBFNTX" )   // Создать БД с использованием механизма NTXDBF

CLOSE ALL
USE TestSDF VIA SDFDBE                       // Открыть с использованием механизма SDF 
USE TestDBF EXCLUSIVE NEW                     // Открыть с использованием механизма SDF 

SELECT TestSDF

*** Запись поля в БД (корректная) ***********
FOR i=1 TO N_Rec
    DBGOTO(i)
    FieldPut( 1, i         )                  // Запись поля в БД (корректная)
    FieldPut( 2, STR(i,15) )                  // Запись поля в БД (корректная)
    FOR j=3 TO N_Col
        FieldPut( j, i*10000+j )              // Запись поля в БД (корректная)
    NEXT
NEXT

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

FOR i=1 TO N_Rec
    DBGOTO(i)
    FOR j=1 TO N_Col
        Fv = FIELDGET(j)
    NEXT
NEXT

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

nTimeON := SECONDS()
FOR i=1 TO N_Rec
    FOR j=1 TO N_Col
        DBGOTO(i);Fv = FIELDGET( j )
        DBGOTO(i);FieldPut( j, Fv )              // Запись поля в БД (корректная)
    NEXT
NEXT
nTimeOFF := SECONDS()
MsgBox("Время исполнения для БД.TXT="+ALLTRIM(STR(nTimeOFF-nTimeON))+" сек.")

nTimeON := SECONDS()

SELECT TestDBF
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

CLOSE ALL

RETURN NIL

Re: Closing the database opened with FOpen

Posted: Sat Aug 24, 2013 2:19 pm
by Auge_Ohr
Eugene Lutsenko wrote:

Code: Select all

#include 'dmlb.ch'
#include 'SdfDbe.ch'

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

FUNCTION Main()
...
you include 'SdfDbe.ch' but where is your DBESYS ?

you have to use DbeInfo() and DbeBuild() when DbeSetDefault( "SDFDBE" )

Re: Closing the database opened with FOpen

Posted: Sat Aug 24, 2013 10:37 pm
by Eugene Lutsenko
Everything is working. Used both dbf, and sdf database. Problem one: It works only with very small dimensions N_Cls, N_Rec

Code: Select all

#include 'dmlb.ch'
#include 'SdfDbe.ch'

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

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

LOCAL Getlist := {}, oProgress, oDialog

DC_IconDefault(1000)

DbeSetDefault( "DBFNTX" )

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

N_Cls   = 5                // Число классов
N_Rec   = 10               // Число признаков

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

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

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 })
AADD(aStructure, { "Sredn", "N", 19, 2 })
AADD(aStructure, { "Disp" , "N", 19, 2 })

**************************************

DbCreate( "TestSDF", aStructure, "SDFDBE" )   // Создать БД с использованием механизма SDF 
DbCreate( "TestDBF", aStructure, "DBFNTX" )   // Создать БД с использованием механизма NTXDBF

CLOSE ALL
USE TestSDF EXCLUSIVE NEW VIA 'SDFDBE';ZAP    // Открыть с использованием механизма SDF 
USE TestDBF EXCLUSIVE NEW VIA 'DBFNTX'        // Открыть с использованием механизма SDF 

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

****** Создание пустой БД.sdf для измерения скорости обращения
SELECT TestSDF
FOR i=1 TO N_Rec
    APPEND BLANK
    FieldPut( 1, i         )                  // Запись поля в БД (корректная)
    FieldPut( 2, STR(i,15) )                  // Запись поля в БД (корректная)
    FOR j=3 TO N_Col
        FieldPut( j, i*10000+j )              // Запись поля в БД (корректная)
    NEXT
NEXT

****** Создание пустой БД.dbf для измерения скорости обращения
SELECT TestDBF
FOR i=1 TO N_Rec
    APPEND BLANK
    FieldPut( 1, i         )                  // Запись поля в БД (корректная)
    FieldPut( 2, STR(i,15) )                  // Запись поля в БД (корректная)
    FOR j=3 TO N_Col
        FieldPut( j, i*10000+j )              // Запись поля в БД (корректная)
    NEXT
NEXT

******* Определение скорости обращения на чтение-запись строки-столбцы "в разброс"
nTimeON := SECONDS()
FOR i=1 TO N_Rec
    FOR j=1 TO N_Col
        DBGOTO(i);Fv = FIELDGET( j )
        DBGOTO(i);FieldPut( j, Fv )           // Запись поля в БД (корректная)
    NEXT
NEXT
nTimeOFF := SECONDS()
MsgBox("Время исполнения для БД.TXT="+ALLTRIM(STR(nTimeOFF-nTimeON))+" сек.")


nTimeON := SECONDS()
FOR i=1 TO N_Rec
    FOR j=1 TO N_Col
        DBGOTO(i);Fv = FIELDGET( j )
        DBGOTO(i);FieldPut( j, Fv )           // Запись поля в БД (корректная)
    NEXT
NEXT
nTimeOFF := SECONDS()
MsgBox("Время исполнения для БД.DBF="+ALLTRIM(STR(nTimeOFF-nTimeON))+" сек.")

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

CLOSE ALL

RETURN NIL

Re: Closing the database opened with FOpen

Posted: Sat Aug 24, 2013 11:34 pm
by Auge_Ohr
Eugene Lutsenko wrote:Everything is working. Used both dbf, and sdf database. Problem one: It works only with very small dimensions N_Cls, N_Rec
you still does not use DbeInfo() and DbeBuild() .
have a look at x:\ALASKA\XPPW32\Source\samples\basics\DBE\sdf.prg and write your own DBESYS.PRG