ReadFile/String vom Ende der Datei?

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
Fox
Beiträge: 75
Registriert: 08.08.2007 10:14
Kontaktdaten:

ReadFile/String vom Ende der Datei?

Beitrag von Fox »

Hallo PureBoard!
Ich hadere nun schon eine ganze Zeit bei einem Problem, welches sich aus meinem Vorhaben ergibt.
Eine Textdatei soll an 2 Stellen um mehrere Zeilen Inhalt ergänzt werden. Die erste Ergänzung soll dabei vor dem String"Mode" erfolgen, jedoch ausschließlich davor und einmalig. Am Ende der Datei soll eine Ergänzung um 2 Strings bei dem String "M5" erfolgen, auch hier einmalig. Da innerhalb der Datei sowohl der String "Mode" als auch der String "M5" mehrmals vorkommen, die Datei aber Zeile für Zeile ausgelesen und mittels ReplaceString dabei jeder String mit dem entsprechendem Inhalt ersetzt wird, ergibt sich das Problem. Daher die Frage, gibt es eine Möglichkeit die Datei und deren Strings vom Ende der Datei aus zu lesen? Oder eine eleganter Lösung?
Benutzeravatar
ProgOldie
Beiträge: 236
Registriert: 19.05.2012 17:09
Computerausstattung: Windows11, Arduinos, Pi3, PureBasic 6.02

Re: ReadFile/String vom Ende der Datei?

Beitrag von ProgOldie »

Die Art der Lösung hängt davon ab, wie groß die Textdatei ist.
a) Bei kleinen Dateien: Alle Zeilen in den Speicher lesen, bearbeiten und dann komplett neu in die Datei zurückschreiben.
b) Bei größeren Dateien: Zunächst eine neue (temp-Datei) anlegen. Dann die ursprüngliche Datei durchlesen und dabei immer einige Zeilen ins RAM. Dann diese bearbeiten und anschließend an die temp-Datei anhängen. Zum Schluss die temp-Datei abspeichern. Das funktioniert bei jeder Dateigröße.

Das einzige Problem bei b) könnte ein ggf. zeitkritisches sein, weil ja die ganze Datei zeilenweise gelesen werden muss.

Und was das Lesen "vom Ende her" betrifft, da gibt es FILESEEK(), das besonders praktisch ist, wenn man die Länge der (Text-)Zeilen kennt. Beispiel aus der Hilfe:

Code: Alles auswählen

file$ = OpenFileRequester("Select a file","","Text (.txt)|*.txt|All files (*.*)|*.*",0)
  If file$
    If ReadFile(0, file$)
      length = Lof(0)                       ; read length of file
      FileSeek(0, length - 10)              ; set the file pointer 10 chars from end of file
      Debug "Position: " + Str(Loc(0))      ; show actual file pointer position
      *MemoryID = AllocateMemory(10)        ; allocate the needed memory for 10 bytes
      If *MemoryID
        bytes = ReadData(0, *MemoryID, 10)  ; read this last 10 chars in the file
        Debug PeekS(*MemoryID)
      EndIf
      CloseFile(0)
    EndIf
  EndIf
Windows10 / PB5.70 / Arduino (-Due) / Raspberry Pi3 /Linux Mint 18
Benutzeravatar
Fox
Beiträge: 75
Registriert: 08.08.2007 10:14
Kontaktdaten:

Re: ReadFile/String vom Ende der Datei?

Beitrag von Fox »

Danke für die schnelle Antwort. Die Textdateien sind im Schnitt 7-15MB groß, daher dauert es logischerweise etwas bis die Datei eingelesen ist.
Die beiden Strings die am Ende der Datei stehen sollen, werden immer in die vorletzte Zeile der Datei geschrieben.
Ist folgende Überlegung sinnvoll?
Schleife von 0-49, d.h. Datei von Zeile 0 bis Zeile 50 einlesen und mittels WriteStringN(), wenn ReadString(0) = “Mode”, die einzufügenden Strings in die Datei schreiben.
Anschließend Zeile 51 bis Ende der Datei lesen und in die Datei schreiben.
Nun zwei Zeilen über dem Eof die anderen beiden Strings einfügen und die Datei schließen.

Würde das funktionieren oder bin ich komplett auf dem Holzweg?
Die Zeilenlängen in der Quelldatei sind übrigens variabel und nicht bekannt.
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: ReadFile/String vom Ende der Datei?

Beitrag von ts-soft »

Erst mal die Textdatei richtig schnell einlesen, sonst wird das nichts /:->

Crossplattform wäre dann mit ReadData(), natürlich die ganze Datei einlesen, suchen tun wir wenn die Datei eingelesen wurde!

Oder für Windows in ein Control:

Code: Alles auswählen

Procedure StreamFileIn_Callback(hFile, pbBuff, cb, pcb)
  ProcedureReturn ReadFile_(hFile, pbBuff, cb, pcb, 0)!1
EndProcedure

Procedure Editor_Load(Gadget, File.s)
  Protected FileID = ReadFile(#PB_Any, File)
  Protected StreamData.EDITSTREAM
  If FileID
    StreamData\dwCookie = FileID(FileID)
    StreamData\dwError = #Null
    StreamData\pfnCallback = @StreamFileIn_Callback()
    If UCase(GetExtensionPart(File)) = "RTF"
      SendMessage_(GadgetID(Gadget), #EM_STREAMIN, #SF_RTF, @StreamData)
    Else
      SendMessage_(GadgetID(Gadget), #EM_STREAMIN, #SF_TEXT, @StreamData)
    EndIf
    CloseFile(FileID)
  EndIf
EndProcedure

If OpenWindow(0, #PB_Ignore, #PB_Ignore, 640, 480, "Editor-Test", #PB_Window_SystemMenu | #PB_Window_Invisible)
    EditorGadget(0, 5, 5, WindowWidth(0) - 10, WindowHeight(0) - 10)
    Editor_Load(0, #PB_Compiler_Home + "SDK\Readme.txt")
   
    While WindowEvent() : Wend
    HideWindow(0, #False)
   
    While WaitWindowEvent() <> #PB_Event_CloseWindow : Wend
EndIf 
Das geht natürlich auch "Superschnell", vor allem im Vergleich mit Zeilenweise einlesen.

Jetzt z.B. den Suchen... Dialog im EditorGadget starten oder nach LF$ im Speicher von hinten suchen um Zeilen zu bilden.

Auf jeden Fall haste erstmal einen Anfang.

Gruß
Thomas
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
Fox
Beiträge: 75
Registriert: 08.08.2007 10:14
Kontaktdaten:

Re: ReadFile/String vom Ende der Datei?

Beitrag von Fox »

Vielen Dank Thomas, hat mir super geholfen und ich bin zum gewünschten Ergebnis gelangt.
Antworten