AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Textdatei zum Lesen & Schreiben öffnen

Ein Thema von glkgereon · begonnen am 14. Mär 2007 · letzter Beitrag vom 15. Mär 2007
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von glkgereon
glkgereon

Registriert seit: 16. Mär 2004
2.287 Beiträge
 
#1

Textdatei zum Lesen & Schreiben öffnen

  Alt 14. Mär 2007, 10:23
Hi,

Ich möchte eine TextDatei öffnen.
Mein Ideal wäre folgendes:
- Öffnen zum lesen und schreiben gleichzeitig
- Zeilenweise auslesen/reinschreiben (wichtig!)
- An bestimmte Zeile springen (Seek o.ä. für Zeilen)
- Einfügen in datei (wäre das nonplusultra^^)

Was ich nicht brauche ist byteweiser Zugriff...

Was nehme ich da am besten?
öffnen und schreiben gleichzeitig fällt textfile raus
zeilenweise fällt FileStream raus


was könnt man da noch nehmen?
»Unlösbare Probleme sind in der Regel schwierig...«
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.166 Beiträge
 
Delphi 12 Athens
 
#2

Re: Textdatei zum Lesen & Schreiben öffnen

  Alt 14. Mär 2007, 10:40
TStringList, damit wäre auch Einfügen/Entfernen gelöst.

Abgesehn von #13#10, #13, #10 und den anderen "Zeilenvorschüben" wird alles Byte für Byte (unverändert) verwaltet.
Und ein Byteweiser Zugriff wäre auch realisierbar ... entweder Stückchenweise/Zeilenweise, oder mit der Text-Eigenschaft über alles.


am Anfang alles per LoadFromFile da reinladen,
dann wild drin rumlesen/-ändern
und zum Schluß mit SaveToFile alles zurück in die Datei
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von Andidreas
Andidreas

Registriert seit: 27. Okt 2005
1.110 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#3

Re: Textdatei zum Lesen & Schreiben öffnen

  Alt 14. Mär 2007, 12:03
oder mein vorschlag denn ich immer wieder erwähne...

ein 2. temporäres textfile erstellen in dem die änderungen gespeichert werden, original löschen, temp in original umbenennen....
Ein Programmierer Programmiert durchschnittlich 15 Code Zeilen pro Tag
Wir sind hier doch nicht bei SAP!!!

Aber wir habens bald
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.166 Beiträge
 
Delphi 12 Athens
 
#4

Re: Textdatei zum Lesen & Schreiben öffnen

  Alt 14. Mär 2007, 12:18
Zitat von Andidreas:
ein 2. temporäres textfile erstellen in dem die änderungen gespeichert werden, original löschen, temp in original umbenennen....
geht aber nur, wenn man die Datei der Reihe nach abarbeitet und man nicht später rückwirkend an einer vorherigen Stelle was machen will.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von glkgereon
glkgereon

Registriert seit: 16. Mär 2004
2.287 Beiträge
 
#5

Re: Textdatei zum Lesen & Schreiben öffnen

  Alt 14. Mär 2007, 14:10
Ähm ja, das hatte ich vergessen

Das ganze soll eine art Buffering werden.
d.h. ich will einen Editor haben welcher nicht die gesamte Datei im Speicher hat.
Daher kommt es ebenfalls nicht in Frage die gesamte Datei (TStringList) zu laden.
»Unlösbare Probleme sind in der Regel schwierig...«
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.166 Beiträge
 
Delphi 12 Athens
 
#6

Re: Textdatei zum Lesen & Schreiben öffnen

  Alt 14. Mär 2007, 14:34
Da wird es dann etwas schwieriger, wenn du die Anzahl/Länge der Strings in einem Teilbereich ändern willst.

Also entweder doch mit 2 Dateien und dann per ReadLn in der einen einlesen und per WriteLn in die andere Schreiben ... und dann halt Zeilen zwischenschieben, bzw. unerwünschte Zeilen einfach nicht mehr speichern.


- ansonsten mußt du ja die Datei selber nach einem Zeilenwechsel nahe der gewünschten Blockgröße durchsuchen
- dann den Bereich einlesen
- ändern...
- je nach Längenänderung des Blocks die nachfolgenden Daten in der Datei verschieben
- den Block speichern
- nach diesem Block dann den nächsten Zeilenwechsel suchen
- dann den Bereich einlesen
.....
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von glkgereon
glkgereon

Registriert seit: 16. Mär 2004
2.287 Beiträge
 
#7

Re: Textdatei zum Lesen & Schreiben öffnen

  Alt 14. Mär 2007, 15:09
Also es sollte so funktionieren:

Code:
Buffer an Stelle P laden:
Start = ScrollToLineStart(P - BufSize div 2)
Stop = ScrollToLineEnd(P + BufSize div 2)
Buffer = Copy(Start,Stop)

Buffer zurückschreiben:
Start = ScrollToLineStart(P - BufSize div 2)
Stop = ScrollToLineEnd(P + BufSize div 2)
Schieben(Stop,Size(Buffer)-BufSize) //Bytes ab Stelle Stop um x Bytes verschieben
Write(Buffer,Start)
Nur: Schieben???

[Edit]
Eine andere Änderung war folgendes:
den Text teilweise in Ram laden, aber NICHT ändern.
sozusagen bearbeitung im readonly-mode und die änderung werden entsprechend gespeichert...(wie wäre noch die frage)
beim speichern würden dann einfach die änderungen nach dem auftreten in der datei sortiert und die datei einmal von vorne nach hinten durchgeackert...

oder eine weitere möglichkeit (da ganze soll ein Editor für SEHR große dateien werden) die Datei read-only zu öffnen und bearbeiten nur als überschreiben zuzulassen (=länge konstant) und löschen oder einfügen nur als sonderfunktion ausserhalb des eigentlichen editors...
»Unlösbare Probleme sind in der Regel schwierig...«
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.166 Beiträge
 
Delphi 12 Athens
 
#8

Re: Textdatei zum Lesen & Schreiben öffnen

  Alt 14. Mär 2007, 15:28
Mir fängt eh grad der Kopf vor Treibern an zu rauchen ...
mal sehn ob ich schnell 'ne kleine Klasse zusammenbekomm. ^^

*Abwechslung brauch*
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von glkgereon
glkgereon

Registriert seit: 16. Mär 2004
2.287 Beiträge
 
#9

Re: Textdatei zum Lesen & Schreiben öffnen

  Alt 14. Mär 2007, 16:15
Ich hatte grad schon wieder ne neue Idee

Eine verkette Liste mit Strings...

Delphi-Quellcode:
TLine = class
  Next, Prev: TLine;
  Text: String;
  Changed: Boolean; //2 Byte?
end;
jedes repräsentiert eine Zeile...
Vorteil:
man könnte einmal die Datei "analysieren" und sich die Liste aufbauen (erzeugt natürlich Overhead 10 Byte pro Zeile ist leider nicht wenig... )

Nun wird zum Laden einfach mittels eines gemoddeten TFileStreams zur x'ten Zeile gesprungen (x = Pos-(Bufsize div 2)) und mittels FS.ReadLn geladen. Alles was ausserhalb des gebufferten Bereichs liegt und nicht geändert wurde wird geleert (Text:=''

Somit befindet sich immer nur der Overhead, die gebufferten Zeilen und die geänderten Zeilen im Speicher. Ich denke deutlich besser geht es nicht^^
Beispielrechung (Das Beispiel ist eine (der kleineren) Datei die ich vorliegen hab, also durchaus realistisch ):
2 Mio Zeilen
ca. 50 Zeichen/Zeile
1000 Zeilen editiert
Buffer: 100000 Zeilen

Dateigröße: 2Mio * 50 = 100MB
Overhead: 10*2Mio = 20MB
Buffer: 100000*50 = 5MB
Geändert: 1000*50 = 50KB (Die höchstwahrscheinlich schon im Buffer sind)

Das ganze ist eigentlich genial:
Einfügen von Zeilen ist dank der verketteten Liste ein Kinderspiel, einfügen von Buchstaben kann in handlichen Stücken (in der Zeile) erfolgen. Löschen ist ebenfalls kein Problem.

Einziges Problem ist das Speichern, aber auch das sollte gar nicht so schwer sein...Mein Ansatz: Speichern in eine neue Datei, alte Datei löschen, neue umbenennen, fertig.
Also Zeile für Zeile durchgehen, falls was im Buffer steht das nehmen, ansonsten aus der alten Datei lesen.
Event. sogar das 2-Dateien-System an den User weitergeben und mit einer "Quelldatei" und einer "Arbeitsdatei" basteln lassen.

Nun, was natürlich stört ist die Dateigröße...
event. wäre es ja möglich die liste nur so groß zu machen wie der Buffer ist und somit den overhead auf ein minimum beschränken...
allerdings ist dann das mit dem ändern nicht mehr so schön einfach :-/
ideen?
»Unlösbare Probleme sind in der Regel schwierig...«
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.166 Beiträge
 
Delphi 12 Athens
 
#10

Re: Textdatei zum Lesen & Schreiben öffnen

  Alt 14. Mär 2007, 17:08
OK, das wäre och noch 'ne Möglichkeit ... hast'e da inzwischen schon was zusammen?

hier mal meine Klasse.
- ist bisher aber noch nicht getestet worden
(nur im Kopf entstanden ... ich hoff mal da sind keine großen Denkfehler drin)
- aber der Compiler meckert schonmal nicht

Overhead wäre hierbei "nur" der aktuell geladene Block,
allerdings würde natürlich beim Speichern eines Blockes eventuell der gesamte nachfolgende Teil verschoben werden.

Delphi-Quellcode:
.
  Type TPartialTextfile = Class
    Private
      _FileName: String;
      _FileHandle: THandle;
      _FileSize, _Start: Int64;
      _OrgLen: Integer;
      _Part: TStringList;
      Function _FindNextLineBreak(Const i: Int64): Integer;
    Public
      Constructor Create;
      Destructor Destroy; Override;
      Property FileName: String Read _FileName;
      Property FileSize: Int64 Read _FileSize;
      Property Start: Int64 Read _Start;
      Property OrgLen: Integer Read _OrgLen;
      Property Part: TStringList Read _Part;
      Function Open (Const FileName: String): Boolean;
      Function LoadPart (Const Pos: Int64; MinLen: Integer): Boolean; Overload;
      Function LoadPart ( {next part} MinLen: Integer): Boolean; Overload;
      Function LoadPartLi(Const Pos: Int64; Lines: Integer): Boolean; Overload;
      Function LoadPartLi( {next part} Lines: Integer): Boolean; Overload;
      Function SavePart: Boolean;
      Procedure Close;
    End;

  Function TPartialTextfile._FindNextLineBreak(Const i: Int64): Integer;
    Var B: Array[0..65535] of Char;
      i2: LARGE_INTEGER;
      W, W2: Cardinal;

    Begin
      Result := 0;
      Repeat
        i2.QuadPart := i + Result;
        i2.LowPart := SetFilePointer(_FileHandle, i2.LowPart, @i2.HighPart, FILE_BEGIN);
        If i2.QuadPart <> i + Result Then Exit;
        ReadFile(_FileHandle, B, SizeOf(B), W, nil);
        If (W <> SizeOf(B)) and (W <> _FileSize - i - Result) Then Exit;
        W2 := 0;
        While W2 < W do Begin
          Inc(W2);
          Case B[W2 - 1] of
            #0, #10: Break;
            #13: Begin
              If W2 > W Then Begin
                i2.QuadPart := i + Result + W2;
                i2.LowPart := SetFilePointer(_FileHandle, i2.LowPart, @i2.HighPart, FILE_BEGIN);
                If i2.QuadPart = i + Result + W2 Then Begin
                  ReadFile(_FileHandle, B, 1, W, nil);
                  If (W = 1) and (B[0] = #10) Then Inc(W2);
                End;
              End Else If B[W2] = #10 Then Inc(W2);
              Break;
            End;
          End;
        End;
        Inc(Result, W2);
      Until W < SizeOf(B);
    End;

  Constructor TPartialTextfile.Create;
    Begin
      _FileHandle := INVALID_HANDLE_VALUE;
      _Part := TStringList.Create;
    End;

  Destructor TPartialTextfile.Destroy;
    Begin
      _Part.Free;
    End;

  Function TPartialTextfile.Open(Const FileName: String): Boolean;
    Var i64: LARGE_INTEGER;

    Begin
      If _FileHandle <> INVALID_HANDLE_VALUE Then Close;
      _FileHandle := CreateFile(PChar(FileName), GENERIC_READ   or GENERIC_WRITE,
        FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0);
      If _FileHandle <> INVALID_HANDLE_VALUE Then Begin
        i64.LowPart := GetFileSize(_FileHandle, @i64.HighPart);
        _FileName := FileName;
        _FileSize := i64.QuadPart;
        Result := True;
      End Else Result := False;
    End;

  Function TPartialTextfile.LoadPart(Const Pos: Int64; MinLen: Integer): Boolean;
    Var S: String;
      W: Cardinal;
      i: LARGE_INTEGER;

    Begin
      Result := False;
      If (_FileHandle = INVALID_HANDLE_VALUE) or (Pos > _FileSize) or (MinLen <= 0) Then Exit;
      Try
        SetLength(S, _FindNextLineBreak(Pos + MinLen));
      Except
        Exit;
      End;
      i.QuadPart := Pos;
      i.LowPart := SetFilePointer(_FileHandle, i.LowPart, @i.HighPart, FILE_BEGIN);
      If i.QuadPart <> Pos Then Exit;
      ReadFile(_FileHandle, S[1], Length(S), W, nil);
      If Length(S) <> Integer(W) Then Exit;
      Try
        _Start := Pos;
        _OrgLen := Length(S);
        _Part.Text := S;
      Except
        _OrgLen := 0;
        _Part.Clear;
        Exit;
      End;
      Result := True;
    End;

  Function TPartialTextfile.LoadPart(MinLen: Integer): Boolean;
    Begin
      Result := LoadPartLi(_Start + _OrgLen, MinLen);
    End;

  Function TPartialTextfile.LoadPartLi(Const Pos: Int64; Lines: Integer): Boolean;
    Var S: String;
      W: Cardinal;
      i: LARGE_INTEGER;

    Begin
      Result := False;
      If (_FileHandle = INVALID_HANDLE_VALUE) or (Pos > _FileSize) or (Lines <= 0) Then Exit;
      W := 0;
      While Lines > 0 do Begin
        Inc(W, _FindNextLineBreak(Pos + W));
        If Integer(W) < 0 Then Exit;
        Dec(Lines);
      End;
      Try
        SetLength(S, W);
      Except
        Exit;
      End;
      i.QuadPart := Pos;
      i.LowPart := SetFilePointer(_FileHandle, i.LowPart, @i.HighPart, FILE_BEGIN);
      If i.QuadPart <> Pos Then Exit;
      ReadFile(_FileHandle, S[1], Length(S), W, nil);
      If Length(S) <> Integer(W) Then Exit;
      Try
        _Start := Pos;
        _OrgLen := Length(S);
        _Part.Text := S;
      Except
        _OrgLen := 0;
        _Part.Clear;
        Exit;
      End;
      Result := True;
    End;

  Function TPartialTextfile.LoadPartLi(Lines: Integer): Boolean;
    Begin
      Result := LoadPartLi(_Start + _OrgLen, Lines);
    End;

  Function TPartialTextfile.SavePart: Boolean;
    Var S: String;
      W, W2: Cardinal;
      B: Array[0..65535] of Char;
      i, i2: LARGE_INTEGER;
      i3: Integer;

    Begin
      Result := False;
      If _FileHandle = INVALID_HANDLE_VALUE Then Exit;
      Try
        S := _Part.Text;
      Except
        Exit;
      End;
      i3 := _OrgLen - Length(S);
      If i3 > 0 Then Begin
        i.QuadPart := _Start + _OrgLen;
        While i.QuadPart < _FileSize do Begin
          i2.QuadPart := i.QuadPart;
          i2.LowPart := SetFilePointer(_FileHandle, i2.LowPart, @i2.HighPart, FILE_BEGIN);
          If i2.QuadPart <> i.QuadPart Then Exit;
          ReadFile(_FileHandle, B, SizeOf(B), W, nil);
          If (W <> SizeOf(B)) and (W <> _FileSize - i.QuadPart) Then Exit;
          W2 := W;
          i2.QuadPart := i.QuadPart - i3;
          i2.LowPart := SetFilePointer(_FileHandle, i2.LowPart, @i2.HighPart, FILE_BEGIN);
          If i2.QuadPart <> i.QuadPart - i3 Then Exit;
          WriteFile(_FileHandle, B, W2, W, nil);
          If W <> W2 Then Exit;
          Inc(i.QuadPart, SizeOf(B));
        End;
      End Else If i3 < 0 Then Begin
        i3 := -i3;
        i.QuadPart := _Start + _OrgLen;
        Inc(i.QuadPart, (_FileSize - i.QuadPart) and -SizeOf(B));
        While i.QuadPart >= _Start + _OrgLen do Begin
          i2.QuadPart := i.QuadPart;
          i2.LowPart := SetFilePointer(_FileHandle, i2.LowPart, @i2.HighPart, FILE_BEGIN);
          If i2.QuadPart <> i.QuadPart Then Exit;
          ReadFile(_FileHandle, B, SizeOf(B), W, nil);
          If (W <> SizeOf(B)) and (W <> _FileSize - i.QuadPart) Then Exit;
          W2 := W;
          i2.QuadPart := i.QuadPart + i3;
          i2.LowPart := SetFilePointer(_FileHandle, i2.LowPart, @i2.HighPart, FILE_BEGIN);
          If i2.QuadPart <> i.QuadPart + i3 Then Exit;
          WriteFile(_FileHandle, B, W2, W, nil);
          If W <> W2 Then Exit;
          dec(i.QuadPart, SizeOf(B));
        End;
      End;
      Dec(_FileSize, i3);
      i.QuadPart := _FileSize;
      i.LowPart := SetFilePointer(_FileHandle, i.LowPart, @i.HighPart, FILE_BEGIN);
      If i.QuadPart = _FileSize Then SetEndOfFile(_FileHandle);
      i.QuadPart := _Start;
      i.LowPart := SetFilePointer(_FileHandle, i.LowPart, @i.HighPart, FILE_BEGIN);
      If i.QuadPart <> _Start Then Exit;
      WriteFile(_FileHandle, S[1], Length(S), W, nil);
      _OrgLen := Length(S);
      Result := Length(S) <> Integer(W);
    End;

  Procedure TPartialTextfile.Close;
    Begin
      CloseHandle(_FileHandle);
      _FileName := '';
      _FileHandle := INVALID_HANDLE_VALUE;
      _FileSize := 0;
      _Start := 0;
      _OrgLen := 0;
      _Part.Clear;
    End;
Delphi-Quellcode:
// Edit: TEdit;
// Button1: TButton;

  Procedure TForm1.Button1Click(Sender: TObject);
    Var PT: TPartialTextfile;

    Begin
      PT := TPartialTextfile.Create;
      PT.Open('Unit1.pas');
      Memo1.Lines.Clear;
      Repeat
        PT.LoadPartLi(10);
        Memo1.Lines.Add(Format('*** %d, %d/%d', [PT.Start, PT.OrgLen, Length(PT.Part.Text)]));
        Memo1.lines.AddStrings(PT.Part);
        Memo1.Lines.Add('');
      Until PT.Part.Text = '';
      PT.Free;
    End;
[edit]
Fehler im Code behoben
das Auslesen funktioniert anscheinend
und auch eine kleine Testprozedur ist nun mit dabei


[add]
wenn du die geänderten Strings erstmal hinter dem "originalem" Dateiende in der Datei speicherst, dann würde auch einer dieser beiden Varianten für deine Idee ausreichen ... außerdem würden die dann nicht im RAM liegen, was bei vielen Änderungen in großen Dateien besser wäre.
Delphi-Quellcode:
PLine = ^TLine;
TLine = packed record
  Next, Prev: PLine;
  TextPos: Int64;
  TextLen: Integer;
end;

TLineArray = Array of Record
  TextPos: Int64;
  TextLen: Integer;
end;
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:58 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz