Entwickler-Ecke

Dateizugriff - Textdatei rückwärts auslesen


Amiga-Fan - Fr 18.03.05 15:36
Titel: Textdatei rückwärts auslesen
wisst Ihr vielleicht wie man eine Textdatei rückwärts auslesen kann ohne die gesamten Daten im Speicher zu halten? Ich habe es versucht.... In ein Array einlesen würde zu viel Arbeitsspeicher kosten (die Textdatei ist immerhin 13 MB groß).

ich habe ein Importprogramm und das schreibt die INSERT und zugehörigen DELETE (um das ganze wieder rückgängig zu machen) - Befehle in jeweils eine separate Datei. Aber wenn ich mit dem Delete-Skript das Einfügen rückgängig machen will muß ich das natürlich rückwärts angehen.


retnyg - Fr 18.03.05 15:38

gehe mit seek an das (eof des files) - 1, und dann immer ein char einlesen, mit seek wieder ein byte zurück usw


delfiphan - Fr 18.03.05 15:53

Ich würde auch retnyg's Vorschlag probieren.
Was auch ginge: Du kannst dir einen Bereich im Virtual Memory Space direkt einer Datei zuordnen. Wenn du dann von diesem Memorybereich liest, wird nicht vom RAM sondern von der Festplatte gelesen. Du kannst dann im Delphi ein normales Array definieren - wenn du darauf zugreifst, wird direkt von einer Datei gelesen oder geschrieben!
Siehe memory mapped files (mmap/munmap) auf msdn oder Google. Habs aber selbst noch nie probiert.


Amiga-Fan - Fr 18.03.05 15:59

Danke. Hm klappt noch nicht, in der Zieldatei stehen nur Nullen oder Einsen :D


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
    
var
    QuellDatei:file of Byte;
    ZielDatei: Textfile;
    tmpChar:byte;
begin
  try
    AssignFile(QuellDatei,sFilePath+'Delete.sql');                // SQL-Statement ins Insert.sql Script schreiben
    Reset(QuellDatei);

    DeleteFile(sFilePath+'Delete2.sql');
    AssignFile(ZielDatei,sFilePath+'Delete2.sql');                // SQL-Statement ins Insert.sql Script schreiben
    Rewrite(ZielDatei);

    x:=filesize(QuellDatei)-1;
    while x>=0 do begin
      x:=filesize(QuellDatei)-1;
      seek(Quelldatei,x);
      read(QuellDatei,tmpChar);
      dec(x);
      Write(ZielDatei,tmpChar);
    end;

    CloseFile(QuellDatei);
    CloseFile(ZielDatei);

    [...]


retnyg - Fr 18.03.05 16:00

Zitat:

Delphi-Quelltext
1:
2:
3:
    x:=filesize(QuellDatei)-1;
    while x>=0 do begin
      x:=filesize(QuellDatei)-1;

warum 2mal die filesize lesen ?


Amiga-Fan - Fr 18.03.05 16:02

nur um zu initialisieren, damit er in die Schleife reinspringt.

Habe gerade Textfile durch file of byte ersetzt, reicht aber nicht. Hm wenn ich das so mache wird er vermutlich auch die Befehle rückwärts schreiben, da muss ich mir noch was einfallen lassen...


delfiphan - Fr 18.03.05 16:03

Ausserdem würd ich die Datei nicht Byte-weise lesen, sondern Blockweise.


retnyg - Fr 18.03.05 16:05

user profile iconAmiga-Fan hat folgendes geschrieben:
nur um zu initialisieren, damit er in die Schleife reinspringt.

da sich die filesize nie ändert, wird aber auch X nie NULL sein ?
ich würde das 2te da mal weg machen, und es mit einem file of char probieren.


Amiga-Fan - Fr 18.03.05 16:06

hm seek scheint jedenfalls nur mit file of byte aber nicht mit textfile zu funktionieren...


delfiphan - Fr 18.03.05 16:08

Das Seek funktioniert mit TextFiles nicht. TextFile verwendet zum lesen/schreiben einen Buffer, deswegen kannst du nicht seeken.
(Du musst dir diesen Buffer bei einem file of Char selbst basteln, ausser du willst tatsächlich eine 13mb grosse Datei byteweise lesen...)


Amiga-Fan - Fr 18.03.05 16:18

Zitat:
ich würde das 2te da mal weg machen, und es mit einem file of char probieren.

stimmt denkfehler

jetzt scheints zu funktionieren:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
  
    QuellDatei:file of Byte;
    ZielDatei: file of byte;
    tmpChar:byte;
begin
  try
    AssignFile(QuellDatei,sFilePath+'Delete.sql');                // SQL-Statement ins Insert.sql Script schreiben
    Reset(QuellDatei);

    DeleteFile(sFilePath+'Delete2.sql');
    AssignFile(ZielDatei,sFilePath+'Delete2.sql');                // SQL-Statement ins Insert.sql Script schreiben
    Rewrite(ZielDatei);

    x:=filesize(QuellDatei)-1;
    while x>=0 do begin
      seek(Quelldatei,x);
      read(QuellDatei,tmpChar);
      dec(x);
      Write(ZielDatei,tmpChar);
    end;

    CloseFile(QuellDatei);
    CloseFile(ZielDatei);


Ergebnis:

;'632030000000-6400-5554-1000-66716000'=dItsiHetatSkooB erehw tsiHetatSkooB morf eteleD

;'314110000000-4400-5554-1000-66716000'=dIgnikooB erehw gnikooB morf eteleD

;'067500000000-3400-5554-1000-66716000'=dInoitcasnarTkooB erehw noitcasnarTkooB morf eteleD

Ach wenn man einen Spiegel dagegen hält klappt das schon :lol:
Ich werde das wohl so lassen und zeilenweise einlesen und das dann wieder umdrehen...

Danke für die Hilfe :)


JoachimQ - So 28.08.05 13:50

user profile iconAmiga-Fan hat folgendes geschrieben:
Zitat:
ich würde das 2te da mal weg machen, und es mit einem file of char probieren.

stimmt denkfehler

jetzt scheints zu funktionieren:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
  
    QuellDatei:file of Byte;
    ZielDatei: file of byte;
    tmpChar:byte;
begin
  try
    AssignFile(QuellDatei,sFilePath+'Delete.sql');                // SQL-Statement ins Insert.sql Script schreiben
    Reset(QuellDatei);

    DeleteFile(sFilePath+'Delete2.sql');
    AssignFile(ZielDatei,sFilePath+'Delete2.sql');                // SQL-Statement ins Insert.sql Script schreiben
    Rewrite(ZielDatei);

    x:=filesize(QuellDatei)-1;
    while x>=0 do begin
      seek(Quelldatei,x);
      read(QuellDatei,tmpChar);
      dec(x);
      Write(ZielDatei,tmpChar);
    end;

    CloseFile(QuellDatei);
    CloseFile(ZielDatei);


Ergebnis:

;'632030000000-6400-5554-1000-66716000'=dItsiHetatSkooB erehw tsiHetatSkooB morf eteleD

;'314110000000-4400-5554-1000-66716000'=dIgnikooB erehw gnikooB morf eteleD

;'067500000000-3400-5554-1000-66716000'=dInoitcasnarTkooB erehw noitcasnarTkooB morf eteleD

Ach wenn man einen Spiegel dagegen hält klappt das schon :lol:
Ich werde das wohl so lassen und zeilenweise einlesen und das dann wieder umdrehen...

Danke für die Hilfe :)


DeleteFile(sFilePath+'Delete2.sql'); --> Ich würd vorher noch abfragen ob die Datei überhaupt existiert!!!


reptile - So 14.01.07 15:24

sry dass ich den alten thread nochmal benutze aber der letzte satz da interessiert mich. kann mir jemand sagen wie das geht, also abfragen ob eine datei existiert? die suchfunktion bringt nur diesen einen thread ^^


jaenicke - So 14.01.07 15:35

Ähh, dafür kannst du einen neuen Thread erstellen, dann haben alle was davon...