Seite 1 von 1
FRead() wo liegt da das Ende?
Verfasst: Mo, 30. Apr 2012 7:38
von Manfred
Moin,
es geht immer noch um meine besagte Textdatei. Mittlerweile ist sie 2.149.425.908 Bytes groß. Nachdem ich FReadStr() gegen FRead() ausgetauscht habe, komme ich trotzdem nicht weiter. Es sieht so aus, als wenn die Datei zu groß wäre. Kann es sein? Sie wird doch auch unter 32Bit Windows erzeugt. Anfänglich dachte ich, es wäre ein Steuerzeichen irgendwo falsch drin, aber wenn man den Anfang der Datei kappt, dann läuft das Programm bis zum Ende durch.
Re: FRead() wo liegt da das Ende?
Verfasst: Mo, 30. Apr 2012 8:24
von Markus Walter
Hi Manfred,
der Sinn von fread liegt darin, dass man in einer Schleife auch "kleinere" Portionen einer Datei lesen kann (der Zeiger in der Datei wird immer um die gelesene Anzahl Bytes nach vorne gesetzt). Ich kenne jetzt aber Dein Urspungsproblem nicht wirklich...
Re: FRead() wo liegt da das Ende?
Verfasst: Mo, 30. Apr 2012 9:10
von Manfred
ich lese immer 4k ein und verarbeite sie. Dann Fseek() und dann wieder fread() bis zum Ende. So die Theorie. Aber neuerdings will das nicht mehr so. Deshalb wollte ich wissen, ob die Gesamtgröße der Datei eine Rolle spielt, wenn ich häppchenweise vom Anfang bis zum Ende durchgehend einlese.
vielleicht hilft das weiter?
Code: Alles auswählen
PROCEDURE artuldkonvert(oThread,oPbStart,oPbEnde)
LOCAL aArray := {}
LOCAL cAuszug
LOCAL cBuffer
LOCAL lAbbruch := .F.
LOCAL nLaenge := 0
LOCAL nStelleLF
LOCAL nStelleLF2 := 0
LOCAL oPhnUpdate := phnupdate():new()
MEMVAR oSysPara
oThread:nZeichenLaengeLesen := 4000
oPbEnde:disable()
oPbStart:disable()
oThread:lGestartet := .T.
oPbStart:setCaption("Anfangsposition Datei")
FSeek(oThread:nHandle,0,FS_SET) // an den Anfang
IF ! oSysPara:oMessage:anzeigen("ACHTUNG, die Konvertierung der Daten kann längere Zeit in Anspruch nehmen!" + CRLF +;
"Soll die Konvertierung wirklich gestartet werden?",.T.,"N")
lAbbruch := .T.
ENDIF
IF ! lAbbruch
oThread:nZaehler := 2 // weil Überschrift überspringen wird
oPhnUpdate:db_oeffnen(,.F.,.T.,,.T.,,.T.) // öffnen und immer vorher löschen, für den Fall der Fälle
oPbStart:setCaption("Daten einlesen")
cBuffer := FReadStr(oThread:nHandle,oThread:nZeichenLaengeLesen) // 1.Durchlauf
nStelleLF := AtNum(Chr(10),cBuffer,3,nStelleLF) + 1 // Überschrift übergehen
oPbStart:enable()
oPbStart:setCaption("Stop")
DO WHILE .T.
Sleep(0)
oThread:nZaehler++
IF oThread:nZaehler <= 100
oThread:oZaehler:setData()
ELSEIF oThread:nZaehler <= 1000
IF oThread:nZaehler %100 == 0
oThread:oZaehler:setData()
ENDIF
ELSE
IF oThread:nZaehler %1000 == 0
oThread:oZaehler:setData()
ENDIF
ENDIF
IF oThread:nZaehler = oThread:nMenge
EXIT
ENDIF
IF ! oThread:lGestartet
IF oSysPara:oMessage:anzeigen("Konvertieren abbrechen?",.T.,"N")
lAbbruch := .T. // damit die Artuld.txt nicht gelöscht wird
EXIT
ENDIF
oThread:lGestartet := .T.
ENDIF
nLaenge := AtNum(Chr(10),cBuffer,1,nStelleLF) - nStelleLF
IF nLaenge <= 0
nStelleLF2 += nStelleLF-1 // weil der TExt als soclhes ja länger ist
FSeek(oThread:nHandle,nStelleLF2,FS_SET) // zum letzten Linefeed gehen
FRead(oThread:nHandle,@cBuffer,oThread:nZeichenLaengeLesen) // nächsten Block einlesen
ENDIF
cAuszug := SubStr(cBuffer,nStelleLF,nLaenge)
IF ! Empty(cAuszug)
aArray := Str2Array(cAuszug)
(oPhnUpdate:nArea)->(DbAppend())
(oPhnUpdate:nArea)->v_darstell := aArray[KUENSTLER]
(oPhnUpdate:nArea)->datumvoe := SToD(aArray[VOE])
(oPhnUpdate:nArea)->datumaende := SToD(aArray[AEND])
(oPhnUpdate:nArea)->datumgestr := SToD(aArray[STREICH])
(oPhnUpdate:nArea)->ean13 := Right("0000" + Trim(aArray[EAN_UPC]),13)
(oPhnUpdate:nArea)->fsk := Val(aArray[FS])
(oPhnUpdate:nArea)->hap := Val(aArray[HAP_AKT_CE])/100
(oPhnUpdate:nArea)->label := aArray[LABEL]
(oPhnUpdate:nArea)->neu_ean := aArray[NEUE_EAN_UPC]
(oPhnUpdate:nArea)->phngenre := aArray[GENRE_S_1]
(oPhnUpdate:nArea)->phnprgart := Val(aArray[PAR])
(oPhnUpdate:nArea)->phnsystem := aArray[TART]
(oPhnUpdate:nArea)->setinhalt := Val(aArray[SET])
(oPhnUpdate:nArea)->v_titel := aArray[TITEL]
ELSE
oThread:nZaehler-- // es muß einer abgezogen werden
ENDIF
nStelleLF := AtNum(Chr(10),cBuffer,1,nStelleLF) + 1
ENDDO .T.
oThread:lGestartet := .F.
oPhnUpdate:schliesse_Datenbank()
oThread:oZaehler:setData() // nochmal am Schluß, damit Menge und Zähler vergleichbar sind
IF ! lAbbruch
oSysPara:oMessage:anzeigen("Konvertierung beendet")
ENDIF
ENDIF
FClose(oThread:nHandle) // machen wir hier mal dicht
oPbStart:disable()
oPbEnde:enable()
RETURN
********************************************************************************
FUNCTION Str2Array(cString, cDelim )
LOCAL aRet := {}
LOCAL nX := 1
LOCAL nPos := 0
LOCAL nLen
LOCAL cRet
DEFAULT cDelim TO ";"
nLen := LEN( cString )
cRet := SPACE(nLen)
DO WHILE ( .T. )
nPos := AT(cDelim, cString, nX)
IF nPos > 0
cRet := SubStr(cString, nX, nPos-nX)
AADD(aRet, cRet)
nX := ++nPos
ELSEIF nX <= nLen
cRet := SubStr(cString, nX)
aadd(aRet, cRet)
EXIT
ELSEIF nX > nLen
aadd(aRet, "")
EXIT
ELSE
EXIT
ENDIF
ENDDO
RETURN ( aRet )
Re: FRead() wo liegt da das Ende?
Verfasst: Mo, 30. Apr 2012 9:23
von georg
Hallo, Manfred -
welchen Wert liefert Dir
fSize(oThread:nHandle)
Gruss,
Georg
Re: FRead() wo liegt da das Ende?
Verfasst: Mo, 30. Apr 2012 9:35
von Manfred
Hi Georg,
exact den Wert, den die Datei selbst auch hat.
Re: FRead() wo liegt da das Ende?
Verfasst: Mo, 30. Apr 2012 9:48
von brandelh
Hallo Manfred,
ich habe hier eine Textdatei mit 4.154.687.701 Byte erzeugt. Eingelesen und umkopiert. Das funktioniert, solange man nicht versucht das Dateiende per FSEEK() zu ermitteln:
http://www.alaska-software.com/scripts/ ... PDRID=6383
Quellcode:
Code: Alles auswählen
#include "fileio.ch"
procedure main
local cFileName := "big.txt"
local nSizeExPl := 4154687701
local cSizeExPl := " 4.154.687.701"
local nQuelle, nZiel, nBytes, nSize, cBuffer, nReadByte, x, nReadBytes, nCopyBytes
cls
set alternate to TestBigLog.txt
set alternate on
nBytes := 4096
cBuffer := space(nBytes)
?
? "Test der low level file Funktionen"
? cFileName
? "Größe laut Explorer: ",transform(nSizeExPl,"999,999,999,999"), " (numerisch)"
? "Größe laut Explorer: ",cSizeExPl, " (string)"
nQuelle := FOpen( cFileName , FO_READ )
nSize := FSeek( nQuelle, 0 , FS_END ) // gehe zum Ende
? "Größe laut FSEEK(): ", transform(nSize, "999,999,999,999"), " (numerisch)"
? "Wieder am Anfang: ", FSeek( nQuelle, 0 , FS_SET ) // gehe zum Anfang
nBytes := 4096
cBuffer := space(nBytes)
nZiel := FCreate( "NeueDatei.TXT", FC_NORMAL )
IF nZiel == -1
? "Fehler beim Erzeugen der Datei:", FError()
ELSE
x := 1
nReadBytes := 0
nCopyBytes := 0
do while nBytes > 0
if x > 100
@ 1, 40 say "gelesen: "+transform(nReadBytes, "999,999,999,999")
@ 2, 40 say "kopiert: "+transform(nCopyBytes, "999,999,999,999")
x := 1
else
x++
endif
nBytes := FRead(nQuelle, @cBuffer, len(cBuffer))
nReadBytes += nBytes
if FError() > 0
? "LESEN - FError() = ",FError()
exit
endif
nBytes := FWrite(nZiel, @cBuffer, nBytes)
nCopyBytes += nBytes
if FError() > 0
? "SCHREIBEN - FError() = ",FError()
exit
endif
enddo
ENDIF
FClose( nQuelle )
FClose( nZiel )
@ 1, 40 say "gelesen: "+transform(nReadBytes, "999,999,999,999")
@ 2, 40 say "kopiert: "+transform(nCopyBytes, "999,999,999,999")
? "Gelesen: ",transform(nReadBytes, "999,999,999,999")
? "Kopiert: ",transform(nCopyBytes, "999,999,999,999")
set alternate off
set alternate to
wait
return
Ergebnis, man beachte den Wert hinter "Größe laut FSEEK(): "
Code: Alles auswählen
Test der low level file Funktionen
big.txt
Größe laut Explorer: 4.154.687.701 (numerisch)
Größe laut Explorer: 4.154.687.701 (string)
Größe laut FSEEK(): -140.279.595 (numerisch)
Wieder am Anfang: 0
Gelesen: 4.154.687.701
Kopiert: 4.154.687.701
Re: FRead() wo liegt da das Ende?
Verfasst: Mo, 30. Apr 2012 9:53
von Manfred
Also kann ich auf jeden Fall ausschließen, dass "meine" Textdatei zu groß ist.
Re: FRead() wo liegt da das Ende?
Verfasst: Mo, 30. Apr 2012 10:25
von brandelh
Wenn man FSize() benutzt bekommt man die richtige Größe geliefert:
Code: Alles auswählen
FSize(cFileName)
FSize(nQuelle)
nSize := FSize(nQuelle)
Re: FRead() wo liegt da das Ende?
Verfasst: Mo, 30. Apr 2012 10:58
von Herbert
Manfred,
Kriegst du einen Fehlercode mit Ferror()?
Und wieso machst du ein Fseek? Das fread positioniert den Pointer von selbst.
Du füllst den Buffer zuerst mit FreadStr. Das heisst, du liest ein bis zum ersten CHR(0) oder der gegebenen Länge.
Falls du also auf ein Chr(0) stösst, ist cBuffer zu klein, da fread mit @cBuffer dann zu klein ist.
IF nLaenge <= 0
nStelleLF2 += nStelleLF-1 // weil der TExt als soclhes ja länger ist
FSeek(oThread:nHandle,nStelleLF2,FS_SET) // zum letzten Linefeed gehen
cBuffer:=SPACE(nZeichenLaengeLesen) // richtige Länge definieren!
FRead(oThread:nHandle,@cBuffer,oThread:nZeichenLaengeLesen) // nächsten Block einlesen
ENDIF
Vielleicht hilfts!
Re: FRead() wo liegt da das Ende?
Verfasst: Mo, 30. Apr 2012 11:55
von Rolf Ramacher
Hallo Manfred,
warum liest du die Datei nicht mit memoread - und läufst die dann mit for next durch
Re: FRead() wo liegt da das Ende?
Verfasst: Mo, 30. Apr 2012 13:40
von brandelh
Ich habe mein Testprogramm von oben eben mit einer 6 GB Datei laufen lassen, gleiches Ergebnis.
Re: FRead() wo liegt da das Ende?
Verfasst: Mo, 30. Apr 2012 13:50
von brandelh
Rolf Ramacher hat geschrieben:Hallo Manfred,
warum liest du die Datei nicht mit memoread - und läufst die dann mit for next durch
weil seine Datei ...
Manfred hat geschrieben:Moin,
es geht immer noch um meine besagte Textdatei. Mittlerweile ist sie 2.149.425.908 Bytes groß.
für direktes Einlesen zu groß bzw. bald zu groß sein wird.
Die Geschwindigkeit beim Zerhacken riesiger Dateien (über 500 MB) ist auch nicht schneller,
also 4 Kilobyte Blocks einzulesen und diese zu zerhacken, da sonst andauernd auf Festplatte aus und eingelagert werden muss ...
Manfred,
du solltest aber "Sprünge" mit FSEEK() auf jeden Fall meiden.
Es könnte zwar gehen, wenn man mehrere kleine macht, aber die Neupositionierung kostet (relativ) viel Zeit (verwerfen des Festplatten/Windows cache).
Einfach die 4 KByte Zeichenkette zerschneiden wenn man nicht mit Zeiger darin arbeiten will
Re: FRead() wo liegt da das Ende?
Verfasst: Mo, 30. Apr 2012 15:00
von Manfred
Hm,
dann habe ich irgendwas falsch interpretiert. Ich war der Meinung ich müßte immer neu positionieren, weil ich ja nicht immer bis zum Endezeichen lese.
Re: FRead() wo liegt da das Ende?
Verfasst: Mo, 30. Apr 2012 16:04
von brandelh
Manfred hat geschrieben:weil ich ja nicht immer bis zum Endezeichen lese.
FALSCH, du übergibst die Anzahl der gewünschten Bytes und erhälst die Anzahl der gelesenen (in @cBuffer).
Der Satzzeiger liegt nun auf dem nächsten zu lesenen Zeichen GENAU RICHTIG
Natürlich wird das fast immer nicht dein gewünschtes Zeilenende etc. sein, das kannst du aber leicht intern ausgleichen.
Bei meinen Tests hat der 4096 Byte Buffer immer sehr gute Werte geliefert, ab und zu sind größere Buffer etwas schneller,
teilweise aber auch langsamer ...
Re: FRead() wo liegt da das Ende?
Verfasst: Mo, 30. Apr 2012 16:37
von Markus Walter
Manfred hat geschrieben:Hm,
dann habe ich irgendwas falsch interpretiert. Ich war der Meinung ich müßte immer neu positionieren, weil ich ja nicht immer bis zum Endezeichen lese.
Sowohl fread, als auch freadstr verschieben den Zeiger automatisch. freadstr bricht aber den Lesevorgang bei einem chr(0) ab, was fread nicht tut.
Re: FRead() wo liegt da das Ende?
Verfasst: Mo, 30. Apr 2012 16:54
von Manfred
Das ist mir alles schon klar, aber ich springe doch über den gewünschten Punkt hinaus und lese weiter als ich eigentlich müßte.
Ich werde mir das nochmal genau im Debugger ansehen, ich denke da habe ich irgendwas in den falschen Hals gekriegt.
Re: FRead() wo liegt da das Ende?
Verfasst: Mo, 30. Apr 2012 16:55
von Herbert
Herbert hat geschrieben:
Und wieso machst du ein Fseek? Das fread positioniert den Pointer von selbst.
Manfred, liest du denn wirklich unsere Einträge?
Re: FRead() wo liegt da das Ende?
Verfasst: Mo, 30. Apr 2012 17:06
von Manfred
Herbert,
doch ich lese eure Einträge. Aber lesen heißt nicht immer gleich verstehen.
Re: FRead() wo liegt da das Ende?
Verfasst: Mo, 30. Apr 2012 17:50
von brandelh
Nochmals für MANFRED
Ich zerhacke die Datei immer in 4096 Byte Stücke, diese Stücke werden beim ersten Aufruf aus
1. Datensatz | 2. Datensatz | ... X. Datensatz ANFANG
beim nächsten Aufruf wird fast immer (außer du forderst genau ein vielfaches der fixen Satzlänge) der Rest des letzen Datensatzes und so weiter stehen...
X. Datensatz ENDE | X+1. Datensatz | X+2. Datensatz | ... Y. Datensatz ANFANG ....
irgendwann kommt dann ...
Y. Datensatz ENDE | Y+1. Datensatz | Y+2. Datensatz | ... Letzer Datensatz
Im Buffer suchst du beim ersten mal also einfach den ersten Datensatz, nimmst den und machst auf den Rest ein substr() ...
danach immer den Rest + neuer buffer und wieder verarbeiten solange was da ist.
Die Zuordnung wird in relativ kurzen Strings erledigt (max 4 KB ) und geht daher recht schnell.
Solltest du eine feste Satzlänge haben könntest du natürlich immer so wenige Daten anfordern, aber das wäre viel langsamer.
Re: FRead() wo liegt da das Ende?
Verfasst: Di, 01. Mai 2012 1:14
von AUGE_OHR
@Manfred : AtNum() ist doch aus Xbtools ? ein besonderer Grund warum du nicht AT() verwendest ?
Re: FRead() wo liegt da das Ende?
Verfasst: Di, 01. Mai 2012 9:19
von Manfred
Jimmy,
nicht wirklich. Mal sehen warum ich das gemacht habe.
Re: FRead() wo liegt da das Ende?
Verfasst: Mi, 02. Mai 2012 3:49
von AUGE_OHR
ich verwende ja die "vorhandenen" Demo Function (siehe FSeek() ) so
Code: Alles auswählen
aFile := F_Use( cFile ) // Datei öffnen
F_GoBottom( aFile )
nLengh := aFile[ F_POS ]
F_GoTop( aFile )
DO WHILE ! F_Eof( aFile )
cBuffer := F_Read( aFile, nMaxBuff )
nPointer := AT(CRLF,cBuffer, nLastPos) // hier CRLF als "Trenner"
cBuffer := SUBSTR(cBuffer,1,nPointer)
//re-positionieren
nLastPos := FSeek( aFile[F_HANDLE], nLastPos+nPointer+1 , FS_SET )
aFile[F_POS] := nLastPos
Tumalwas(cBuffer,aText)
// ist das Ende erreicht ?
IF aFile[F_POS] >= aFile[F_LASTREC]
EXIT
ENDIF
ENDDO
FClose( aFile[F_HANDLE] )
die "Schleife" und die "Verarbeitung" trenne ich gerne um es "universell" verwenden zu können.
Re: FRead() wo liegt da das Ende?
Verfasst: Mi, 02. Mai 2012 7:28
von Manfred
So wie es jetzt aussieht, steht mal wieder an irgendeiner Stelle "Schrott". Wie ich diese Textdatei hasse.
Re: FRead() wo liegt da das Ende?
Verfasst: Mi, 02. Mai 2012 7:59
von Paul Brem
Hallo Manfred
Die Funktion FSeek( <nHandle>, <nOffset>, [<nOrigin>] ) und damit auch FRead etc.
kann nur bis zu einem nOffset von 2147483648 betrieben werden.
Eine grössere Datei kann daher nicht vernünftig verarbeitet werden.
Man müsste dazu auf ein 64Bit API gehen.
Gruss Paul
Re: FRead() wo liegt da das Ende?
Verfasst: Mi, 02. Mai 2012 8:08
von brandelh
Paul Brem hat geschrieben:Eine grössere Datei kann daher nicht vernünftig verarbeitet werden.
Man müsste dazu auf ein 64Bit API gehen.
Solange man sequenziell einliest oder schreibt (wie ich in meinem Beispiel oben) ist das kein Problem !