DATANORM V4/V5 Artikel - Textfile
Moderator: Moderatoren
-
- Rekursionen-Architekt
- Beiträge: 246
- Registriert: Mi, 04. Jun 2014 12:01
- Wohnort: FRANKEN
DATANORM V4/V5 Artikel - Textfile
Guten Morgen ,
ich bins wieder mal .
Habe hier eine etwa 60MB große DATANORM Datei welche in das Programm eingelesen wird welches ich hier von Clipper auf Xbase Fenstermodus umschreibe.
Es wird folgendermaßen in die aktuelle Artikel DBF Datenbank eingelesen:
File wird Zeile für Zeile eingelesen (zerlegt ) und in eine DBF Datenbank zwischengespeichert.
Danach wird die zwischengespeicherte Datanorm . DBF mit dem vorhanden Artikelstamm abgeglichen -> Artikel neu anlegen bzw aktualisieren !
--- nur der Einlesevorgang dauert jetzt schon ne STUNDE ...
Außerdem habe ich dazu eine DATANORM.RAB ( Rabatt Datei ) welche anscheinend neu ist bzw noch nie berücksichtigt worden ist
Gibt es da schon was fertiges wo ich nur meine Datanbank Felder zuweisen muß oder so .... ?
Mit Array sollte es wohl schneller gehen , aber ich lese hier ständig was von SPEICHERÜBERLAUF , der natürlich nicht erwünscht ist ...
Hat jemand Erfahrung damit bzw kann mich jemand in die richtige Richtung treten
Für Denkanstöße wäre ich dankbar !
mfg Klaus
ich bins wieder mal .
Habe hier eine etwa 60MB große DATANORM Datei welche in das Programm eingelesen wird welches ich hier von Clipper auf Xbase Fenstermodus umschreibe.
Es wird folgendermaßen in die aktuelle Artikel DBF Datenbank eingelesen:
File wird Zeile für Zeile eingelesen (zerlegt ) und in eine DBF Datenbank zwischengespeichert.
Danach wird die zwischengespeicherte Datanorm . DBF mit dem vorhanden Artikelstamm abgeglichen -> Artikel neu anlegen bzw aktualisieren !
--- nur der Einlesevorgang dauert jetzt schon ne STUNDE ...
Außerdem habe ich dazu eine DATANORM.RAB ( Rabatt Datei ) welche anscheinend neu ist bzw noch nie berücksichtigt worden ist
Gibt es da schon was fertiges wo ich nur meine Datanbank Felder zuweisen muß oder so .... ?
Mit Array sollte es wohl schneller gehen , aber ich lese hier ständig was von SPEICHERÜBERLAUF , der natürlich nicht erwünscht ist ...
Hat jemand Erfahrung damit bzw kann mich jemand in die richtige Richtung treten
Für Denkanstöße wäre ich dankbar !
mfg Klaus
- brandelh
- Foren-Moderator
- Beiträge: 15699
- Registriert: Mo, 23. Jan 2006 20:54
- Wohnort: Germersheim
- Hat sich bedankt: 68 Mal
- Danksagung erhalten: 34 Mal
- Kontaktdaten:
Re: DATANORM V4/V5 Artikel - Textfile
Das zeilenweise Einlesen ist problematisch, die 60 MB kann man leicht auf einen Schlag in ein Array laden,
Eine Zeile ergibt dann ein Array-Element. Es könnte problematisch werden, wenn die Anzahl der Zeilen sehr hoch ist.
http://www.xbaseforum.de/viewtopic.php?f=16&t=4268
Es macht aber eventuell auch Sinn das gleich aus der eingelesenen Datei zu machen.
Hast du mehr Infos zum Aufbau ?
Im obigen Beispiel kannst du sehen wie die Datei auf einen Schlag eingelesen wird (in eine Variable, das braucht keine Sekunde bei 50 MB).
Aus dieser Variable werden dann die VON / BIS Werte für eine Zeile berechnet, der String selbst aber nicht geändert.
Diese VON BIS Werte könntest du nutzen um die Daten einer Zeile zu erhalten und per Programm direkt in deine Anwendungsdaten einpflegen.
Das macht aber natürlich nur Sinn, wenn das einmalig geschieht. Wenn DU einmalig Update-DBFs einliest und dann versendest, dann nicht.
100.000 eindimensionale Arrayelemente können Problematisch sein, bei mehr Dimmensionen und Strings geht es vorher in die Knie.
500 MB im RAM sind kein Problem wenn man ab 2 GB Hauptspeicher hat UND der String nur gelesen nicht aber geändert wird !
Eine Zeile ergibt dann ein Array-Element. Es könnte problematisch werden, wenn die Anzahl der Zeilen sehr hoch ist.
http://www.xbaseforum.de/viewtopic.php?f=16&t=4268
Es macht aber eventuell auch Sinn das gleich aus der eingelesenen Datei zu machen.
Hast du mehr Infos zum Aufbau ?
Im obigen Beispiel kannst du sehen wie die Datei auf einen Schlag eingelesen wird (in eine Variable, das braucht keine Sekunde bei 50 MB).
Aus dieser Variable werden dann die VON / BIS Werte für eine Zeile berechnet, der String selbst aber nicht geändert.
Diese VON BIS Werte könntest du nutzen um die Daten einer Zeile zu erhalten und per Programm direkt in deine Anwendungsdaten einpflegen.
Das macht aber natürlich nur Sinn, wenn das einmalig geschieht. Wenn DU einmalig Update-DBFs einliest und dann versendest, dann nicht.
100.000 eindimensionale Arrayelemente können Problematisch sein, bei mehr Dimmensionen und Strings geht es vorher in die Knie.
500 MB im RAM sind kein Problem wenn man ab 2 GB Hauptspeicher hat UND der String nur gelesen nicht aber geändert wird !
Gruß
Hubert
Hubert
-
- Rekursionen-Architekt
- Beiträge: 246
- Registriert: Mi, 04. Jun 2014 12:01
- Wohnort: FRANKEN
Re: DATANORM V4/V5 Artikel - Textfile
Code: Alles auswählen
A;N;10000002;00;Westaflex Grobfilter WAC G4;o Sommerbypassklappe, f 250WACCF, 2 Stck;1;0;ST;2037;6630;231;;
B;N;10000002;000CFFILT002;000CFFILT002; ;0;0;0;4024875118659; ;231903;0;1; ; ;
A;N;10000003;00;Westaflex Grobfilter WAC G4;m Sommerbypassklappe, f 250WACCF, 2 Stck;1;0;ST;2185;6630;231;;
B;N;10000003;000CFFILT004;000CFFILT004; ;0;0;0;4024875122441; ;231903;0;1; ; ;
A;N;10000004;00;Westaflex 3-Stufenschalter;fr externen Anschluss an 140W;1;0;ST;8272;6630;231;;
B;N;10000004;000CFSBED;000CFSBED; ;0;0;0;2000003259564; ;231903;0;1; ; ;
mfg
- brandelh
- Foren-Moderator
- Beiträge: 15699
- Registriert: Mo, 23. Jan 2006 20:54
- Wohnort: Germersheim
- Hat sich bedankt: 68 Mal
- Danksagung erhalten: 34 Mal
- Kontaktdaten:
Re: DATANORM V4/V5 Artikel - Textfile
wieviele Zeilen hat die Datei in etwa ?
da es eine CSV ist könnte eventuell ein Einlesen über Excel 2007ff. vorteilhaft sein, ein ActiveX Beispiel zum Einlesen von DBF Dateien von Alaska kann man dann abändern.
Für die Zeilen und Zellen weise Übertragung wäre dann aber die ActiveX Variante zu langsam, hier könnte LibXL helfen.
Ansonsten geht auch direktes Übertragen wie oben beschrieben alles in eine Datei oder in 4 KB Blöcken einlesen,
Zeilen ermitteln und Zeilenweise aus dem String lesen. Direkt verarbeiten ... Pablo hat eine Token-Funktion die man leicht nutzen kann, um die Einzelnen Felder aus der Zeile auszulesen.
da es eine CSV ist könnte eventuell ein Einlesen über Excel 2007ff. vorteilhaft sein, ein ActiveX Beispiel zum Einlesen von DBF Dateien von Alaska kann man dann abändern.
Für die Zeilen und Zellen weise Übertragung wäre dann aber die ActiveX Variante zu langsam, hier könnte LibXL helfen.
Ansonsten geht auch direktes Übertragen wie oben beschrieben alles in eine Datei oder in 4 KB Blöcken einlesen,
Zeilen ermitteln und Zeilenweise aus dem String lesen. Direkt verarbeiten ... Pablo hat eine Token-Funktion die man leicht nutzen kann, um die Einzelnen Felder aus der Zeile auszulesen.
Gruß
Hubert
Hubert
- Werner_Bayern
- Der Entwickler von "Deep Thought"
- Beiträge: 2126
- Registriert: Sa, 30. Jan 2010 22:58
- Wohnort: Niederbayern
- Hat sich bedankt: 30 Mal
- Danksagung erhalten: 75 Mal
Re: DATANORM V4/V5 Artikel - Textfile
Das sind A und B Sätze für Artikel, das N steht für Neuanlage. Rabattsätze enthalten Rabatte auf Warengruppen. Beschreibung dazu gibts nur von einem Verlag, sonst nirgends. Musst Dir das Buch kaufen, suche nach Datanorm 5 Satzaufbau. Ist aber inzwischen ein sehr altes, überholtes Format.
es grüßt
Werner
<when the music is over, turn off the lights!>
Werner
<when the music is over, turn off the lights!>
-
- Rekursionen-Architekt
- Beiträge: 246
- Registriert: Mi, 04. Jun 2014 12:01
- Wohnort: FRANKEN
Re: DATANORM V4/V5 Artikel - Textfile
Die Zuteilung hab ich mir mittlerweile aus dem Internet zusammengesucht - das ist noch DATANORM V4Werner_Bayern hat geschrieben:Das sind A und B Sätze für Artikel, das N steht für Neuanlage. Rabattsätze enthalten Rabatte auf Warengruppen. Beschreibung dazu gibts nur von einem Verlag, sonst nirgends. Musst Dir das Buch kaufen, suche nach Datanorm 5 Satzaufbau. Ist aber inzwischen ein sehr altes, überholtes Format.
Soweit scheint er auch alles einzulesen, das Problem ist nur er ließt die Daten schon seit 9.30 Uhr ein
werde dann doch das ganze mal in ein array einlesen !
mfg Klaus
- Koverhage
- Der Entwickler von "Deep Thought"
- Beiträge: 2471
- Registriert: Fr, 23. Dez 2005 8:00
- Wohnort: Aalen
- Hat sich bedankt: 102 Mal
- Danksagung erhalten: 3 Mal
- Kontaktdaten:
Re: DATANORM V4/V5 Artikel - Textfile
Ich würde mal die Einleseroutine posten, denn je nach dem wie Du das in ein Array einliest, braucht es auch so lange.
Gruß
Klaus
Klaus
-
- Rekursionen-Architekt
- Beiträge: 246
- Registriert: Mi, 04. Jun 2014 12:01
- Wohnort: FRANKEN
Re: DATANORM V4/V5 Artikel - Textfile
Es sind ca 380000 Artikel
Das einlesen sieht so aus
Das einlesen sieht so aus
Code: Alles auswählen
select 44
use koe
zap
test:= filestr("datanorm.001")
clear
? "Datenbank wird umgewandelt !"
wait("Weiter mit RETURN !!!")
x=numat("A;N;",test)
a=1
do while .not. a > x
z=atnum("A;N",test,a)
y=atnum("B;N",test,a)
test2:= filestr("datanorm.001",500,z)
test3=beforatnum(";",test2,9,0)
test5=beforatnum(";",test2,10,0)
t1= token(test2,";",2,0)
t2= token(test2,";",4,0)
t3= token(test2,";",5,0)
t4= token(test3,";")
t5= token(test5,";")
t5u=val(t5)/100
test2:= filestr("datanorm.001",500,y)
test8=beforatnum(";",test2,4,0)
test9=beforatnum(";",test2,10,0)
t8= token(test8,";")
t9= token(test9,";")
append blank
replace artikelnr with t1
replace produkt with t2
replace produkt2 with t3
replace Einheit with t4
replace vkpreis with t5u
replace matchcode with t8
replace ean with t9
a=a+1
enddo
- brandelh
- Foren-Moderator
- Beiträge: 15699
- Registriert: Mo, 23. Jan 2006 20:54
- Wohnort: Germersheim
- Hat sich bedankt: 68 Mal
- Danksagung erhalten: 34 Mal
- Kontaktdaten:
Re: DATANORM V4/V5 Artikel - Textfile
Versuche doch einfach mal die Daten mit aBuffer := TxtFile2Array(cDateiName,cConvert) (LINK oben) einzulesen, mal sehen ob das geht und wie lange es dauert.
Allerdings werden 380.000 Arrays wohl nicht wirklich schnell sein und eventuell auch die Grenzen sprengen.
Ich wundere mich oben warum du mehrfach die Datei einliest, vermutlich in Teilen, aber viel zu kleinen.
Bei akutellen Rechnern und Xbase++ sollte der buffer 4096 Zeichen groß sein (4 KByte Block).
Allerdings werden 380.000 Arrays wohl nicht wirklich schnell sein und eventuell auch die Grenzen sprengen.
Ich wundere mich oben warum du mehrfach die Datei einliest, vermutlich in Teilen, aber viel zu kleinen.
Bei akutellen Rechnern und Xbase++ sollte der buffer 4096 Zeichen groß sein (4 KByte Block).
Gruß
Hubert
Hubert
- brandelh
- Foren-Moderator
- Beiträge: 15699
- Registriert: Mo, 23. Jan 2006 20:54
- Wohnort: Germersheim
- Hat sich bedankt: 68 Mal
- Danksagung erhalten: 34 Mal
- Kontaktdaten:
Re: DATANORM V4/V5 Artikel - Textfile
verbessern kann man auch die Einlesung selbst: nicht einzelne Zugriffe für jeden Token, sondern Pablos Funktion nutzen:
http://www.xbwin.com/ot4xbXHlp/
Tokenize( cZeile , ";" ) -> aTokens // ";" kann man auch weg lassen, da es Standard ist.
http://www.xbwin.com/ot4xbXHlp/
Tokenize( cZeile , ";" ) -> aTokens // ";" kann man auch weg lassen, da es Standard ist.
Diese Funktion gibt mit einem Aufruf eine Textzeile als Array zurück, vor der Schleife wird ermittelt oder festgelegt welches Arrayelement zu welchem Feld gehört und alles geht schneller.Split a string based on a given delimiter and return an array with the tokens.
Syntax:
Parameters:
<cStr>
String containing the tokens to extract.
<cDelim>
String with the delimiter characters. ";" by default.
Return Value:
Array with the extracted tokens.
Gruß
Hubert
Hubert
- AUGE_OHR
- Marvin
- Beiträge: 12911
- Registriert: Do, 16. Mär 2006 7:55
- Wohnort: Hamburg
- Hat sich bedankt: 19 Mal
- Danksagung erhalten: 46 Mal
Re: DATANORM V4/V5 Artikel - Textfile
Frage : wird eine Zeile mit CHR(13) und/oder CHR(10) abgeschlossen ?xbaseklaus hat geschrieben:z.B. 3 Artikel schauen so aus ...
Ist am Ende der Datei ein CHR(26) ? CRTL-Z
unter Xbase++ hast du nicht das 64Kb Limit d.h. du könntest > 1GB im Stück per Memoread() ( statt mehrfach FileStr() ) in wenigen Sekunden in Speicher einlesen !
kannst du das nicht Satzweise gleich verarbeiten ?... und in eine DBF Datenbank zwischengespeichert.
das APPEND / REPLACE nimmt viel mehr Zeit ein als die String Verarbeitung und 60 MB ist nun wirklich nicht viel.
gruss by OHR
Jimmy
Jimmy
- brandelh
- Foren-Moderator
- Beiträge: 15699
- Registriert: Mo, 23. Jan 2006 20:54
- Wohnort: Germersheim
- Hat sich bedankt: 68 Mal
- Danksagung erhalten: 34 Mal
- Kontaktdaten:
Re: DATANORM V4/V5 Artikel - Textfile
So ich habe mal eine entsprechende Testdatei zusammengebaut und ein Importprogramm geschrieben.
Mein Testprogramm mit meiner Funktion TxtFile2Array(cDateiName,cConvert)
in Verbindung mit Pablos Tokenize( cZeile , ";" ) und einer EXCLUSIV geöffneten DBF liest das in
einer Minute (AMD 4 Kern mit 3 Ghz, 8 GB RAM und 2,5" Festplatte) oder
sogar 30 Sekunden (INTEL i5-4670, 16 GB RAM und SSD) ein.
Das wichtigste bei solchen Aktionen ist
1. EXCLUSIVER Zugriff auf die DBF, OHNE Index (den baut man später auf wenn man diesen braucht).
2. Im RAM den großen String möglichst nur lesen
3. Textdateien auf einmal in den RAM, oder zumindest in 4 KB Blocks die nur gelesen werden.
Die 755.000 Zeilen hat meine Routine übrigens ohne murren und mit Standard STACK Einstellung eingelesen.
Wenn es deutlich mehr werden, muss man mit der 4 KB Block Methode arbeiten.
Das wäre doch mal wieder eine Klasse wert ...
Mein Testprogramm mit meiner Funktion TxtFile2Array(cDateiName,cConvert)
in Verbindung mit Pablos Tokenize( cZeile , ";" ) und einer EXCLUSIV geöffneten DBF liest das in
einer Minute (AMD 4 Kern mit 3 Ghz, 8 GB RAM und 2,5" Festplatte) oder
sogar 30 Sekunden (INTEL i5-4670, 16 GB RAM und SSD) ein.
Das wichtigste bei solchen Aktionen ist
1. EXCLUSIVER Zugriff auf die DBF, OHNE Index (den baut man später auf wenn man diesen braucht).
2. Im RAM den großen String möglichst nur lesen
3. Textdateien auf einmal in den RAM, oder zumindest in 4 KB Blocks die nur gelesen werden.
Die 755.000 Zeilen hat meine Routine übrigens ohne murren und mit Standard STACK Einstellung eingelesen.
Wenn es deutlich mehr werden, muss man mit der 4 KB Block Methode arbeiten.
Das wäre doch mal wieder eine Klasse wert ...
Gruß
Hubert
Hubert
- brandelh
- Foren-Moderator
- Beiträge: 15699
- Registriert: Mo, 23. Jan 2006 20:54
- Wohnort: Germersheim
- Hat sich bedankt: 68 Mal
- Danksagung erhalten: 34 Mal
- Kontaktdaten:
Re: DATANORM V4/V5 Artikel - Textfile
und die habe ich hier sogar schon im Einsatz ... schneller als die Array Versionbrandelh hat geschrieben:Das wäre doch mal wieder eine Klasse wert ...
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
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)
Gruß
Hubert
Hubert