brandelh hat geschrieben:Das wäre doch mal wieder eine Klasse wert ...
und die habe ich hier sogar schon im Einsatz ... schneller als die Array Version
I5-2500, 8 GB Ram, 3,5" Festplatte:
Array-Version 47 Sekunden (mit Pablos Tokenize(), mein eigener dauert 30 Sekunden länger)
TextRead-Version 30 Sekunden und hier kann man einfach eine Verlaufsanzeige einbauen.
Array-Version:
Code: Alles auswählen
#include "Gra.ch"
#include "Xbp.ch"
#include "Common.ch"
#include "Inkey.ch"
#include "ot4xb.ch"
#ifndef CRLF
#define CRLF chr(13)+chr(10)
#endif
procedure main()
local aBuffer, cFile, aZeile, x, nAnzA, nAnzB, nAnzU, nDauer
field artikelnr, produkt, produkt2, Einheit, vkpreis, matchcode, ean
CLS
SET EXCLUSIVE ON // bei solchen Operationen ist dies 10x schneller !
set alternate to HB-Array.TXT
set alternate on
? time(),"Start"
nDauer := seconds()
cFile := "DATANORM.001"
use KOE EXCLUSIVE
if neterr()
? "KOE.DBF kann nicht geöffnet werden"
quit
endif
ZAP
aBuffer := TxtFile2Array(cFile)
? time(),"DATANORM in aBuffer Array eingelesen, Anzahl Zeilen: ",len(aBuffer)
? time(),"Version:",aBuffer[1]
nAnzA := 0
nAnzB := 0
nAnzU := 0
for x := 2 to len(aBuffer) // Daten
if x = 2 .or. int(x/100) == x/100
? time(),"Zeile:",x,aBuffer[x]
endif
aZeile := Tokenize(aBuffer[x]) // ot4xb.dll einbinden !
* aZeile := Txt2Array(aBuffer[x],";")
do case
case aZeile[1]="A" // scheinbar sind A und B Sätze zu kombinieren !
nAnzA++
append blank
replace artikelnr with aZeile[3] // diese Zuordnung prüfen !
replace produkt with aZeile[5]
replace produkt2 with aZeile[6]
replace Einheit with aZeile[9]
replace vkpreis with val(aZeile[10]) / 100 // scheinbar werden die Beträge in CENT angegeben.
case aZeile[1]="B" // scheinbar sind A und B Sätze zu kombinieren !
nAnzB++
if artikelnr # aZeile[3]
? "B Satz passt nicht zu A Satz !"
endif
replace matchcode with aZeile[4]
replace ean with aZeile[10]
otherwise
nAnzU++
? x,"Unbekannte Satzart:",aZeile[1]," von ",left(aBuffer[x],10)
end
next
? time(),"Ende "
nDauer := seconds()-nDauer
?
? "Anzahl Zeilen (ohne Titel): ",len(aBuffer)-1
? "Anzahl A-Sätze: ",nAnzA
? "Anzahl B-Sätze: ",nAnzB
? "Anzahl unplausibler Sätze: ",nAnzU
?
? "Anzahl Datensätze in DBF: ",Recc()
?
? "Laufzeit ",nDauer,"Sekunden"
?
inkey(20)
return
*-------------------------------------------------------------------------------
FUNCTION TxtFile2Array(cDateiName,cConvert) // TXT einlesen und zeilenweise in Array einlesen
// cConvert: NIL / empty - nichts tun
// O2A - Oem 2 Ansi
// A2O - Ansi 2 Oem
local cDateiInhalt, aZeilen := {}, nVon, nBis, cTxt, nMaxLen
DEFAULT cConvert to ""
nVon := 1
nBis := 0
if file(cDateiName)
cDateiInhalt := memoread(cDateiName)
if ! empty(cDateiInhalt)
cConvert := upper(alltrim(cConvert))
do case
case cConvert == "O2A"
cDateiInhalt := ConvToAnsiCP(cDateiInhalt)
case cConvert == "A2O"
cDateiInhalt := ConvToOemCP(cDateiInhalt)
endcase
nMaxLen := len(cDateiInhalt) // nur einmal aufrufen
do while .t.
nBis := at(CRLF,cDateiInhalt,nVon)
if nBis = 0 // Ende der Datei wurde erreicht, letzten Satz nicht vergessen
cTxt := substr(cDateiInhalt,nVon)
nVon := len(cDateiInhalt)+1
else
cTxt := substr(cDateiInhalt,nVon,nBis-nVon)
nVon := nBis+2
endif
cTxt := strTran(cTxt,CRLF,"") // entferne die CRLF am Zeilenende
aadd(aZeilen,cTxt)
if nVon > nMaxLen
exit
endif
enddo
cDateiInhalt := NIL // sofort als unnötig markieren.
endif
endif
return aZeilen
*-------------------------------------------------------------------------------
FUNCTION Txt2Array(cDateiInhalt,cDelim)
local aZeilen := {}, nVon, nBis, cTxt
DEFAULT cDelim TO CRLF
nVon := 1
nBis := 0
if ! empty(cDateiInhalt)
do while .t.
nBis := at(cDelim,cDateiInhalt,nVon)
if nBis = 0 // Ende der Datei wurde erreicht, letzten Satz nicht vergessen
cTxt := substr(cDateiInhalt,nVon)
nVon := len(cDateiInhalt)+1
else
cTxt := substr(cDateiInhalt,nVon,nBis-nVon)
nVon := nBis+len(cDelim)
endif
cTxt := strTran(cTxt,CRLF,"") // entferne die CRLF am Zeilenende
aadd(aZeilen,cTxt)
if nVon > len(cDateiInhalt)
exit
endif
enddo
endif
return aZeilen
TextReader()
Code: Alles auswählen
#include "ot4xb.ch"
#ifndef CRLF
#define CRLF chr(13)+chr(10)
#endif
* Klasse zum sequentiellen Einlesen groáer Dateien
#IF .t.
procedure main
local nZeile := 0
local cZeile := ""
local nSize, nBytes := 0
local nDauer
local oTR, aZeile, x, nAnzA, nAnzB, nAnzU
field artikelnr, produkt, produkt2, Einheit, vkpreis, matchcode, ean
cls
use KOE EXCLUSIVE
if neterr()
? "KOE.DBF kann nicht geöffnet werden"
quit
endif
ZAP
oTR := TextReader( "DATANORM.001" ) // per Funktion
* oTR := TxtReader():new( "DATANORM.001" ) // oder Klassentypisch !
if oTR:FError() <> 0
@ 1,1 say "Fehler beim Datei ”ffnen: "+oTR:ErrMsg()
quit
endif
nSize := oTR:FSize()
@ 1,1 say "Testdatei sequentiell einlesen"
@ 3,1 say "DateigrӇe "+transform(nSize,"###,###,###,###,###")
@ 4,1 say "Version: "+oTR:GetLine() // 1. Zeile hat Versionsinfos
nDauer := seconds()
nAnzA := 0
nAnzB := 0
nAnzU := 0
do while ! oTR:EOF()
cZeile := oTR:GetLine() // aktuelle Zeile auslesen, interner Zeiger auf nächste Zeile setzen.
* if len(cZeile)=0
* exit
* endif
nZeile++
nBytes += len(cZeile)+2 // CR+LF = 2 Byte
aZeile := Tokenize(cZeile) // ot4xb.dll einbinden !
do case
case aZeile[1]="A" // scheinbar sind A und B Sätze zu kombinieren !
nAnzA++
append blank
replace artikelnr with aZeile[3] // diese Zuordnung prüfen !
replace produkt with aZeile[5]
replace produkt2 with aZeile[6]
replace Einheit with aZeile[9]
replace vkpreis with val(aZeile[10]) / 100 // scheinbar werden die Beträge in CENT angegeben.
case aZeile[1]="B" // scheinbar sind A und B Sätze zu kombinieren !
nAnzB++
if artikelnr # aZeile[3]
@20,1 say str(nZeile)+" B Satz passt nicht zu A Satz !"
endif
replace matchcode with aZeile[4]
replace ean with aZeile[10]
otherwise
nAnzU++
@21,1 say str(nZeile)+" Unbekannte Satzart: '"+aZeile[1]+"' von "+left(cZeile,10)
end
if nZeile % 100 = 0 //
@ 5,1 say "gelesene Bytes "+transform(nBytes,"###,###,###,###,###")
@ 6,1 say "gelesene Zeilen "+transform(nZeile,"###,###,###,###,###")
@ 7,1 say "gelesene A-Zeilen "+transform(nAnzA, "###,###,###,###,###")
@ 8,1 say "gelesene B-Zeilen "+transform(nAnzB, "###,###,###,###,###")
@ 9,1 say "gelesene U-Zeilen "+transform(nAnzU, "###,###,###,###,###")
endif
enddo
oTR:Destroy()
nDauer := seconds() - nDauer
@ 5,1 say "gelesene Bytes "+transform(nBytes,"###,###,###,###,###")
@ 6,1 say "gelesene Zeilen "+transform(nZeile,"###,###,###,###,###")
@ 7,1 say "gelesene A-Zeilen "+transform(nAnzA, "###,###,###,###,###")
@ 8,1 say "gelesene B-Zeilen "+transform(nAnzB, "###,###,###,###,###")
@ 9,1 say "gelesene U-Zeilen "+transform(nAnzU, "###,###,###,###,###")
@10,1 say "Dauer: "+t @11,1 say " "+str(nZeile/nDauer/104)+" Datens„tze / Sekunde"
@13,1 say "ENDE, bitte Taste drcken ..."
wait
return
#endif
* Klasse zum sequentiellen Einlesen großer Dateien
* Da die Blockgröße auf 4 KB begrenzt ist, kann man auch einfach die Zeilen ausschneiden.
#include "Fileio.ch"
function TextReader( cFile )
local oTR := TxtReader():new( cFile )
return oTR
CLASS TxtReader
PROTECTED:
VAR nH
VAR nLastError
VAR IsEOF // Buffer hat beim Einlesen EOF erreicht, Zeilen können noch da sein !
VAR cRest
VAR nBufferBytes // Anzahl der gelesenen Byte im Buffer
VAR cCRLF, nLenCRLF // Unix/Linux nur chr(10) = 1 Byte, Windows chr(13)+chr(10) = 2 Byte
METHOD ReadBuffer
EXPORTED:
METHOD Init
METHOD Destroy
METHOD GetLine
METHOD GoTop
METHOD FSize
METHOD FError
METHOD ErrMsg
METHOD EOF
METHOD IsCrLf
METHOD IsUnix
METHOD IsMac
ENDCLASS
METHOD TxtReader:Init( cFileName ) // Öffnet die Datei zum Lesen
::nLastError := 0
::cRest := ""
::nBufferBytes := 0
::nH := fopen( cFileName , FO_READ + FO_SHARED )
if ::nH = -1
::nLastError := FError()
::IsEOF := .t.
else
::IsEOF := .f.
::ReadBuffer()
do case
case chr(13)+chr(10) $ ::cRest // Windows etc.
::cCRLF := chr(13)+chr(10)
::nLenCRLF := 2
case chr(10) $ ::cRest // Unix
::cCRLF := chr(10)
::nLenCRLF := 1
case chr(13) $ ::cRest // Mac
::cCRLF := chr(13)
::nLenCRLF := 1
end
endif
RETURN SELF
METHOD TxtReader:Destroy()
if ::nH <> -1
FClose(::nH)
::nH := -1
endif
::cRest := ""
RETURN SELF
METHOD TxtReader:ReadBuffer()
local cBuffer, nBufferLen, nBytes
if ::nH > -1
nBufferLen := 4096
cBuffer := space(nBufferLen)
nBytes := FRead( ::nH, @cBuffer, nBufferLen)
cBuffer := StrTran(cBuffer,chr(26)," ")
::nBufferBytes += nBytes
if nBufferLen = nBytes // mitten in Datei
::cRest += cBuffer
else
::cRest += left(cBuffer,nBytes)
::IsEOF := .t.
if FError() <> 0
::nLastError := FError()
endif
endif
cBuffer := ""
endif
Return
METHOD TxtReader:GetLine()
local nPosCRLF
local cLine := ""
do while ! ::cCRLF $ ::cRest .and. ! ::IsEof // Buffer einlesen, bis wir neue Zeilen haben oder die Datei gelesen wurde
::ReadBuffer()
enddo
nPosCRLF := at( ::cCRLF, ::cRest)
if nPosCRLF > 0 // es gibt noch eine komplette Zeile, zurückgeben und kürzen
cLine := left(::cRest,nPosCRLF-1)
::cRest := substr(::cRest,nPosCRLF+::nLenCRLF)
else
cLine := ::cRest
::cRest := ""
endif
return cLine
METHOD TxtReader:GoTop()
if ::nH <> -1
FSeek(::nH, 0 , FS_SET )
endif
::cRest := "" // zwingt zum neu einlesen
::ReadBuffer()
return NIL
METHOD TxtReader:FSize()
local nSize := 0
if ::nH <> -1
nSize := FSize(::nH)
endif
RETURN nSize
METHOD TxtReader:FError()
RETURN ::nLastError
METHOD TxtReader:EOF()
RETURN ::IsEOF .and. empty(::cRest)
METHOD TxtReader:IsCrLf()
RETURN (::cCRLF == chr(13)+chr(10))
METHOD TxtReader:IsUnix()
RETURN (::cCRLF == chr(10))
METHOD TxtReader:IsMac()
RETURN (::cCRLF == chr(13))
METHOD TxtReader:ErrMsg()
RETURN DosErrorMessage(::nLastError)