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. :wink:

Re: FRead() wo liegt da das Ende?

Verfasst: Mo, 30. Apr 2012 17:50
von brandelh
Nochmals für MANFRED :badgrin:

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 !