DBF-Typ bestimmen ...
Moderator: Moderatoren
- brandelh
- Foren-Moderator
- Beiträge: 15697
- Registriert: Mo, 23. Jan 2006 20:54
- Wohnort: Germersheim
- Hat sich bedankt: 66 Mal
- Danksagung erhalten: 33 Mal
- Kontaktdaten:
DBF-Typ bestimmen ...
Hallo,
DBFs gibt es ja in den verschiedensten Ausführungen (dbase3ff (inkl. Clipper und Xbase) mit und ohne DBT und von Foxpro ff.).
Je nach Art, muß man DBFDBE oder FOXDBE benutzen, wobei bei falscher Wahl ein Runtimeerror erfolgt. Die ersten beiden Byte einer DBF geben ja über den Typ auskunft. Hat schon jemand eine Funktion geschrieben, die zumindest die richtige DBE (DBF oder FOX) bestimmen kann ?
Ist ja nicht schwer, aber bevor ich mich da reinhänge frage ich doch mal.
PS: DBINFO() und DBEINFO() funktionieren ja erst nach dem Öffnen, ich möchte die Infos aber bei geschlossener Datei !
DBFs gibt es ja in den verschiedensten Ausführungen (dbase3ff (inkl. Clipper und Xbase) mit und ohne DBT und von Foxpro ff.).
Je nach Art, muß man DBFDBE oder FOXDBE benutzen, wobei bei falscher Wahl ein Runtimeerror erfolgt. Die ersten beiden Byte einer DBF geben ja über den Typ auskunft. Hat schon jemand eine Funktion geschrieben, die zumindest die richtige DBE (DBF oder FOX) bestimmen kann ?
Ist ja nicht schwer, aber bevor ich mich da reinhänge frage ich doch mal.
PS: DBINFO() und DBEINFO() funktionieren ja erst nach dem Öffnen, ich möchte die Infos aber bei geschlossener Datei !
Gruß
Hubert
Hubert
- Martin Altmann
- Foren-Administrator
- Beiträge: 16517
- Registriert: Fr, 23. Sep 2005 4:58
- Wohnort: Berlin
- Hat sich bedankt: 111 Mal
- Danksagung erhalten: 48 Mal
- Kontaktdaten:
Re: DBF-Typ bestimmen ...
Hallo Hubert,
Viele Grüße,
Martin
sowas wird noch keiner geschrieben habenbrandelh hat geschrieben:ich möchte die Infos aber bei geschlossener Datei !
Viele Grüße,
Martin
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/
Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
- Martin Altmann
- Foren-Administrator
- Beiträge: 16517
- Registriert: Fr, 23. Sep 2005 4:58
- Wohnort: Berlin
- Hat sich bedankt: 111 Mal
- Danksagung erhalten: 48 Mal
- Kontaktdaten:
Hallo Jan,
ist mir schon klar - ich konnte mir den Kommentar nur nicht verkneifen (darum auch den am Ende).
Bin halt heut' ein wenig albern - heut' ist der erste Tag meiner Nachtschicht, da muss ich mich noch ein wenig in gute Stimmung bringen
Viele Grüße,
Maritn
ist mir schon klar - ich konnte mir den Kommentar nur nicht verkneifen (darum auch den am Ende).
Bin halt heut' ein wenig albern - heut' ist der erste Tag meiner Nachtschicht, da muss ich mich noch ein wenig in gute Stimmung bringen
Viele Grüße,
Maritn
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/
Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
- Martin Altmann
- Foren-Administrator
- Beiträge: 16517
- Registriert: Fr, 23. Sep 2005 4:58
- Wohnort: Berlin
- Hat sich bedankt: 111 Mal
- Danksagung erhalten: 48 Mal
- Kontaktdaten:
Hallo Jan,
am Ende des Tages läuft ja die Verarbeitung aller Transaktionen über die Nacht hindurch.
Und da werden die kritischen Prozesse natürlich überwacht und auch eingegriffen, sofern nötig.
Da ja auch bei uns eingespart werden soll, wird halt mit wenig Personal gearbeitet. Und wenn von den zuständigen Kollegen auch mal einer Urlaub machen will, dürfen halt auch andere mal ran.
Viele Grüße,
Martin
am Ende des Tages läuft ja die Verarbeitung aller Transaktionen über die Nacht hindurch.
Und da werden die kritischen Prozesse natürlich überwacht und auch eingegriffen, sofern nötig.
Da ja auch bei uns eingespart werden soll, wird halt mit wenig Personal gearbeitet. Und wenn von den zuständigen Kollegen auch mal einer Urlaub machen will, dürfen halt auch andere mal ran.
Viele Grüße,
Martin
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/
Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
- brandelh
- Foren-Moderator
- Beiträge: 15697
- Registriert: Mo, 23. Jan 2006 20:54
- Wohnort: Germersheim
- Hat sich bedankt: 66 Mal
- Danksagung erhalten: 33 Mal
- Kontaktdaten:
Re: DBF-Typ bestimmen ...
Hallo Martin,Martin Altmann hat geschrieben:Hallo Hubert,sowas wird noch keiner geschrieben habenbrandelh hat geschrieben:ich möchte die Infos aber bei geschlossener Datei !
Viele Grüße,
Martin
krieg dich wieder ein vor lachen, ich meine was ich schreibe.
Natürlich muß ich mir mit fopen, fread, fclose die Infos besorgen, aber dabei kann ja nichts schief gehen, solange die DBF überhaupt vorhanden ist - insoweit war ich etwas ungenau.
Gruß
Hubert
Hubert
- Martin Altmann
- Foren-Administrator
- Beiträge: 16517
- Registriert: Fr, 23. Sep 2005 4:58
- Wohnort: Berlin
- Hat sich bedankt: 111 Mal
- Danksagung erhalten: 48 Mal
- Kontaktdaten:
Hallo Jan,
leider nicht ganz. Es sind Laufzeiten zu überwachen und zu protokollieren und ggf. Telefonate zu führen (auch mit London oder New York).
Wenn also alles glatt geht, ist man nur mit schreiben und logfiles prüfen beschäftigt und hat dann und wann auch mal 10 Minuten Zeit, sich einen Tee zu holen oder wegzubringen.
Aber sobald es irgendwo knallt, wird es hektisch. Und wenn dann noch mehr knallt, weiß man nicht, was man zuerst machen soll...
Hubert,
war mir ja schon klar, wie Du das eigentlich meintest
Hast Du schon mal hier geschaut?
Viele Grüße,
Martin
leider nicht ganz. Es sind Laufzeiten zu überwachen und zu protokollieren und ggf. Telefonate zu führen (auch mit London oder New York).
Wenn also alles glatt geht, ist man nur mit schreiben und logfiles prüfen beschäftigt und hat dann und wann auch mal 10 Minuten Zeit, sich einen Tee zu holen oder wegzubringen.
Aber sobald es irgendwo knallt, wird es hektisch. Und wenn dann noch mehr knallt, weiß man nicht, was man zuerst machen soll...
Hubert,
war mir ja schon klar, wie Du das eigentlich meintest
Hast Du schon mal hier geschaut?
Viele Grüße,
Martin
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/
Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
- brandelh
- Foren-Moderator
- Beiträge: 15697
- Registriert: Mo, 23. Jan 2006 20:54
- Wohnort: Germersheim
- Hat sich bedankt: 66 Mal
- Danksagung erhalten: 33 Mal
- Kontaktdaten:
Für TurboBasic habe ich vor 15 Jahren mal eine Funktionssammlung für die Verwaltung von Daten in DBF geschrieben. Von daher habe ich noch recht gute Infos vom Dateiheader, wobei ich heute aus Sicherheitsgründen hingehen werde und mit der DBFDBE und der FOXDBE halt die verschiedenen möglichen DBFs erzeuge (OEM und ANSI) und nachsehe, was im DBF Type eingetragen ist. Eventuell hat ja Alska auch noch was hinzugefügtMartin Altmann hat geschrieben:Hast Du schon mal hier geschaut?
Ich komme drauf, weil ich mich immer tierisch ärgere, wenn ich den DBEDITOR aufrufe und entscheiden soll was es jetzt für eine DBF ist, ohne Indexe (NTX/CDX) und Memofeld ist es gar nicht möglich, ansonsten nicht wirklich sicher. Eine Funktion könnte das ein für alle mal erledigen, ich denke ich werde mal anfangen ...
Gruß
Hubert
Hubert
-
- Cut&Paste-Entwickler
- Beiträge: 37
- Registriert: Do, 19. Okt 2006 10:24
- Wohnort: St. Martin
Hallo Hubert,
ich habe da eine Klasse "DBFCLASS", mir der kannst Du ohne DBE
die Tabelle öffnen und lesen, habe ich schon öffters benötigt um
Daten aus einer defekten Tabelle wieder herauszuholen.
Ich denke die Information steht in irgend einem Byte im Header.
Auf jeden Fall kannst Du mit dieser Klasse und etwas Anpassung
alle Informationen "low level" lesen.
Gruß
Manfred
ich habe da eine Klasse "DBFCLASS", mir der kannst Du ohne DBE
die Tabelle öffnen und lesen, habe ich schon öffters benötigt um
Daten aus einer defekten Tabelle wieder herauszuholen.
Ich denke die Information steht in irgend einem Byte im Header.
Auf jeden Fall kannst Du mit dieser Klasse und etwas Anpassung
alle Informationen "low level" lesen.
Code: Alles auswählen
//----------
// Beispiel
//----------
oDbf := dbfclass():new("m:\temp\rechnung.dbf"):create()
oDbf:dbopen()
oDbf:dbgotop()
do while ! oDbf:eof()
xVal := odbf:ReadFieldbyNum(n)
odbf:dbskipnext(+1)
enddo
odbf:dbclose()
#include "Xbp.ch"
#include "komet.ch"
#include "directry.ch"
#include "class.ch"
#include "Fileio.ch"
//--------------------
// DBF-Tabellen Klasse
//--------------------
CLASS DBFCLASS
PROTECTED:
EXPORTED:
VAR nH // Tabellenhandle
VAR nHMemo // Memofeldhandle
VAR cFile // Filename
VAR cFileMemo // Filename Memo
VAR nSize // Tebellengröße
VAR nRecs // Anzahl Datensätze aus der Headerinfo
VAR nLastrec // Anzahl Datensätze
VAR nHeadersize // Größe des Dateiheaders
VAR nRecsize // Größe eines Datensatzes
VAR cHeader // Dateiheader
VAR nMemoblockSize // Größe des Memoblockes
VAR nTypeMemo // MEO-format 1=DBT 2=FPT
VAR cRecord // Inhalt des aktuelln Datensatzes
VAR nRecord // Aktuelle Datensatznummer
VAR nMaxField // Maximale Feldanzahl
VAR aFields // Array mit Feldinformationen
VAR cLastField // Name des zuletzt zugefriffenen Feldes
VAR nLastField // Nummer des zuletzt zugegriffenen Feldes
VAR lEof // Eof-Status
VAR lBof // Bof-Status
VAR cCache // ReadCache Puffer
VAR nCacheRec // ReadCache Recordanzahl
VAR nCacheRecFirst // Erster Datensatz im Cache
VAR nCacheRecLast // Letzter Datensatz im Cache
//----------------------
// Object initialisieren
//----------------------
INLINE METHOD init(cFile)
::nH := 0
::nHMemo := 0
::nSize := 0
::nRecs := space(4)
::nLastrec := 0
::nHeadersize := space(2)
::nRecsize := space(2)
::cHeader := ""
::nRecord := 0
::nMaxField := 0
::aFields := {}
::cLastField := ""
::nLastField := 0
::nMemoBlockSize := 0
::nTypeMemo := 0
::cFile := ltrim(trim(cFile))
::lEof := .f.
::lBof := .f.
::cCache := ""
::nCacheRec := 1000
::nCacheRecFirst := 0
::nCacheRecLast := 0
if upper(right(::cFile,4)) != ".DBF"
::cfile := ::cfile +".dbf"
endif
//--------------------
// Name der Memo-Datei
//--------------------
if file(left(::cFile,len(::cFile)-3)+"FPT")
::cfileMemo :=left(::cFile,len(::cFile)-3)+"FPT"
::nTypeMemo := 2
elseif file(left(::cFile,len(::cFile)-3)+"DBT")
::cfileMemo :=left(::cFile,len(::cFile)-3)+"DBT"
::nTypeMemo := 1
endif
//? "CLass new",::cfile
RETURN SELF
//-----------------
// Objekt erstellen
//-----------------
INLINE METHOD create()
RETURN SELF
//---------------
// Objekt löschen
//---------------
INLINE METHOD destroy()
if ::nH > 0
fClose(::nH)
endif
::nh := 0
if ::nHMemo > 0
fClose(::nHMemo)
endif
::nhMemo := 0
RETURN SELF
//-------------------
// Tabelle Schliessen
//-------------------
INLINE METHOD dbclose()
::destroy()
RETURN SELF
//---------------
// Tabelle öffnen
//---------------
INLINE METHOD dbopen()
local n := 0 ,nC := 0,cOut
local cField,cType,nLen,nDec,cLen,cDec,cSizeM
local nF,cOff,nOff:=0,nSizeRec:=1
//? ::cFile,"vor öffnen.."
::nh := fOpen(::cFile,FO_READWRITE)
if ::nH < 1
::nh := fOpen(::cFile)
endif
if ::nH > 0
//? ::cFile,"offen.."
//-------------
// Header lesen
//-------------
::nSize:= fileSize(::cFile)
FSeek( ::nH, 4 )
FRead( ::nH, @::nRecs, 4 )
FRead( ::nH, @::nHeaderSize, 2 )
FRead( ::nH, @::nRecSize, 2 )
::nRecs := Bin2L( ::nRecs )
::nHeaderSize := Bin2W( ::nHeaderSize )
::nRecSize := Bin2W( ::nRecSize )
::nLastRec := int((::nSize-1-::nHeadersize)/::nRecsize)
::cHeader := space(::nHeaderSize)
::cCache := space(::nRecSize*::nCacheRec)
::nMaxfield := int( ((::nHeaderSize-2)/32)-1 )
//-----------------
// Felder bestimmen
//-----------------
cField := ""
nC := 0
nF := 0
fseek(::nH,0,FS_SET)
fread(::nH,@::cHeader,::nHeadersize)
cOut := ""
for n:= 1 to ::nHeaderSize
if n >32
nC++
endif
if nC==1
nF++
cField := padr(token(strtran(substr(::cHeader,n ,10),chr(0)," "),1),10," ")
cType := substr(::cHeader,n+11,01)
cOff := substr(::cHeader,n+12,02)
if cType=="C"
cLen := substr(::cHeader,n+16,02)
nLen := Bin2W( cLen)
nDec := 0
else
cLen := substr(::cHeader,n+16,01)
cDec := substr(::cHeader,n+17,01)
nLen := Bin2L( cLen)
nDec := Bin2L( cDec)
endif
//nOff := Bin2W( cOff)+1
//? "Feld","["+cField+"]",cType,padl(nLen,4,"0"),padl(nDec,2,"0"),"Offset",padl(nOff+2,4,"0")
aaDD(::aFields,{cField,cType,nLen,nDec,nOff+2})
nSizeRec := nSizeRec+nLen
if nF==::nMaxfield
exit
endif
nOff := nOff + nlen
endif
/*
if n <= 32
cOut := padl(n,4,"0")+"-"+padl(asc(::cHeader[n]),3,"0")+"["+::cHeader[n]+"]"
? cOut
endif
*/
if nC==32
nC := 0
endif
next n
//-----------------
// Memodatei öffnen
//-----------------
if ::cFileMemo != NIL
::nhMemo := fOpen(::cFileMemo,FO_READWRITE)
if ::nHMemo < 1
::nhMemo := fOpen(::cFileMemo)
endif
if ::nhMemo > 0
if ::nTypeMemo==1
::nMemoBlockSize := 512
elseif ::nTypeMemo==2
cSizeM := space(2)
FSeek( ::nHMemo, 6 )
FRead( ::nHMemo, @cSizeM, 2 )
::nMemoBlockSize := asc(csizeM[1])*256+asc(csizeM[2])
endif
endif
//? "Memfile",::cFileMemo,::nhMemo
endif
/*
? "[Tabelle ]" ,::cFile
? "[Header ]" ,::nHeadersize
? "[Recsize ]" ,::nRecSize
? "[Felder ]" ,::nMaxField
? "[Filesize ]" ,::nSize
? "[Records ]" ,::nLastRec
? "[Blocksize]" ,::nMemoBlockSize
? "[Memotype ]" ,::nTypeMemo
? "Länge aus Feldern",nSizeRec
*/
endif
RETURN SELF
//------------------------------------
// Zu einem bestimmten Datensatz gehen
//------------------------------------
INLINE METHOD dbGoTo(nRec)
local nRead
if nRec >= ::nCacheRecFirst .and. nRec <= ::nCacheRecLast .and. ::nCacheRecfirst > 0
//---------------------------------
// Datensatz befindet sich im Cache
//---------------------------------
::nRecord := nRec
::lEof :=.f.
::lBof :=.f.
else
if nRec < 1
::cCache := space(::nRecSize*::nCacheRec)
::lBof := .t.
::nRecord := 0
::nCacheRecFirst := 0
::nCacheRecLast := 0
elseif nRec > ::nLastrec
? "Resize",::nRecSize
::cCache := space(::nRecSize*::nCacheRec)
::lEof := .t.
::nRecord := 0
::nCacheRecFirst := 0
::nCacheRecLast := 0
else
//----------------
// Cache neu lesen
//----------------
fseek(::nH,::nHeadersize+((nRec-1)*::nRecsize),FS_SET)
nRead := fread(::nH,@::cCache,::nRecSize*::nCacheRec)
if nRead >= ::nRecSize
::nCacheRecFirst := nRec
::nCacheRecLast := nRec + int(nRead/::nRecSize)-1
::nRecord := nRec
::lEof :=.f.
::lBof :=.f.
else
::cCache := space(::nRecSize*::nCacheRec)
::nCacheRecFirst := 0
::nCacheRecLast := 0
::lEof := .t.
::nRecord := 0
endif
endif
endif
RETURN SELF
//-------------------
// Zum Tabellenanfang
//-------------------
INLINE METHOD dbGoTop()
::dbGoto(1)
RETURN SELF
//-----------------
// Zum Tabellenende
//-----------------
INLINE METHOD dbGoBottom()
::dbGoto(::nLastrec)
RETURN SELF
//---------------------------
// Datensatz vorwärts bewegen
//---------------------------
INLINE METHOD dbskipNext()
if ::nRecord < ::nLastrec
::dbGoto(::nRecord+1)
else
::lEof :=.t.
endif
RETURN SELF
//----------------------------
// Datensatz rückwärts bewegen
//----------------------------
INLINE METHOD dbskipPrev()
if ::nRecord > 1
::dbGoto(::nRecord-1)
else
::lBof :=.t.
endif
RETURN SELF
//-----------------------------------------------------------
// aktuelle Datensatznummer ohne Berücksichtigung von Filtern
//-----------------------------------------------------------
INLINE METHOD Recno()
RETURN ::nRecord
//----------------------------------------------------
// Anzahl Datensätze ohne Berücksichtigung von Filtern
//----------------------------------------------------
INLINE METHOD Lastrec()
//--------------------
// Größe neu bestimmen
//--------------------
::nSize := fileSize(::cFile)
::nLastRec := int((::nSize-1-::nHeadersize)/::nRecsize)
RETURN ::nLastrec
//-------------
// EOF - Status
//-------------
INLINE METHOD eof()
RETURN ::lEof
//-------------
// BOF - Status
//-------------
INLINE METHOD bof()
RETURN ::lBof
//-----------------
// DELETED - Status
//-----------------
INLINE METHOD Deleted()
local lDel := .f.
if ::GetRecordAsString()[1]=="*"
lDel := .t.
endif
RETURN lDel
//-------------------------------
// aktueller Datensatz als String
//-------------------------------
INLINE METHOD GetRecordAsString()
return substr(::cCache, 1 + ((::nRecord - ::nCacheRecFirst)*::nRecSize) ,::nRecSize)
//---------------------------------
// Prüfen ob Feldname vorhanden ist
//---------------------------------
INLINE METHOD isFieldName(cField)
local lRet := .f.
local n
if ::nH > 0
cField := padr(upper(cField),10," ")
for n:=1 to ::nMaxfield
if ::aFields[n][1]==cField
lRet := .t.
exit
endif
next n
end
RETURN lRet
//-------------------
// Feldwert ermitteln
//-------------------
INLINE METHOD ReadFieldbyName(cField,lKonv)
local xRet
local n,nBlock,nRecOffSet
if ::nH > 0
cField := padr(upper(cField),10," ")
if ::cLastField==cField
nRecOffSet := ((::nRecord - ::nCacheRecFirst)*::nRecSize)
xRet := substr(::cCache,nRecOffSet+::aFields[::nLastField][5],::aFields[::nLastField][3])
n := ::nLastField
else
for n:=1 to ::nMaxfield
if ::aFields[n][1]==cField
nRecOffSet := ((::nRecord - ::nCacheRecFirst)*::nRecSize)
xRet := substr(::cCache,nRecOffSet+::aFields[n][5],::aFields[n][3])
::cLastField := cField
::nLastField := n
exit
endif
next n
endif
//-----------------
// Typkonvertierung
//-----------------
if lKonv==NIL
lKonv := .t.
endif
if lKonv .and. xRet != NIL
if ::aFields[n][2]=="N"
xRet := val(xRet)
elseif ::aFields[n][2]=="D"
xRet := stod(xRet)
elseif ::aFields[n][2]=="L"
xRet := if(xRet=="T",.t.,.f.)
elseif ::aFields[n][2]=="M"
nBlock := val( xRet)
? "Block",nBlock
if nBlock > 0
xRet := ::ReadMemoBlock(nBlock)
else
xRet := ""
endif
endif
endif
endif
RETURN xRet
//-------------------
// Feldwert ermitteln
//-------------------
INLINE METHOD ReadFieldbyNum(nField,lKonv)
local xRet,nBlock,nRecOffSet
nRecOffSet := ((::nRecord - ::nCacheRecFirst)*::nRecSize)
xRet := substr(::cCache,nRecOffSet+::aFields[nField][5],::aFields[nField][3])
//-----------------
// Typkonvertierung
//-----------------
if lKonv==NIL
if ::aFields[nField][2]=="N"
xRet := val(xRet)
elseif ::aFields[nField][2]=="C"
elseif ::aFields[nField][2]=="D"
xRet := stod(xRet)
elseif ::aFields[nField][2]=="L"
xRet := if(xRet=="T",.t.,.f.)
elseif ::aFields[nField][2]=="M"
nBlock := val( xRet)
if nBlock > 0
xRet := ::ReadMemoBlock(nBlock)
else
xRet := ""
endif
endif
endif
RETURN xRet
//-------------------
// Memoblock auslesen
//-------------------
INLINE METHOD ReadMemoBlock(nBlock)
local cRet := ""
local cRead := ""
local n := 0
local cSize := Space(4)
local nSize := 0
local xRead
local xPos
if ::nhMemo >0
if ::nTypeMemo==1
//----
// DBT
//----
fseek(::nHMemo,0+(nBlock*::nMemoBlockSize),FS_SET)
//------------------------------------------------------
// Werte bis zum nächsten CTRL-Z oder Dateiende einlesen
//------------------------------------------------------
cRead := space(1)
do while fread(::nHMemo,@cRead,1) > 0
if asc(cRead)==26
exit
else
cRet := cRet+cRead
endif
enddo
cRet:=trim(cRet)
elseif ::nTypeMemo==2
//----
// FPT
//----
xPos := fseek(::nHMemo,0+4+(nBlock*::nMemoBlockSize),FS_SET)
xRead := fread(::nHMemo,@cSize,4)
nSize := (asc(cSize[3]))*256+asc(cSize[4])
//? "Size",nSize,::nMemoBlockSize,xRead,"POS",::nHMemo,0+4+(nBlock*::nMemoBlockSize),xPos
cRet := space(nSize)
xRead := fread(::nHMemo,@cRet,nSize)
//? "Gelesen",xRead
endif
endif
Return cRet
ENDCLASS
Manfred