Entwickler-Ecke

Dateizugriff - mehrere StringGrids in Textdatei speichern und öffnen


addlehead - Do 02.03.06 20:24
Titel: mehrere StringGrids in Textdatei speichern und öffnen
Hallo Leute!
hier sind meine Typen, die dazu dienen meine daten, die ich aus 3 stringgrids auslese, speichere:

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:
unit Unit2;
interface
type
t_rechnung=record
Datum:string[10];
Typ:string[15];
Betrag:integer;
Zahlungsweise:string[15];
end;

t_feld2004 =array[0..1000of t_rechnung;
t_feld2005 =array[0..1000of t_rechnung;
t_feld2006 =array[0..1000of t_rechnung;
t_datei= file of t_rechnung;
t_datname=string;
var
v_rechnung2004:t_feld2004;
v_rechnung2005:t_feld2005;
v_rechnung2006:t_feld2006;
v_dat:t_datei;
v_dateiname:t_datname;

implementation

end.


...in v_rechnung2004,v_rechnung2005,v_rechnung2006 schreibe ich im folgenden Code die Daten der entsprechenden StringGrids...


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:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
procedure TForm1.Speichern1Click(Sender: TObject);
var rechnung2004,rechnung2005,rechnung2006: t_rechnung;
         i,j: integer;
begin
//Daten ins record schreiben
for i:=1 to (stringgrid1.RowCount-1do
begin
//2004
v_rechnung2004[i].Datum:=stringgrid1.Cells[1,i];
v_rechnung2004[i].Typ:=stringgrid1.Cells[2,i];
//v_rechnung2004[i].Betrag:=strtoint(stringgrid1.cells[3,i]);
v_rechnung2004[i].Zahlungsweise:=stringgrid1.Cells[4,i];
//2005
v_rechnung2005[i].Datum:=stringgrid2.Cells[1,i];
v_rechnung2005[i].Typ:=stringgrid2.Cells[2,i];
//v_rechnung2005[i].Betrag:=strtoint(stringgrid2.cells[3,i]);
v_rechnung2005[i].Zahlungsweise:=stringgrid2.Cells[4,i];
//2006
v_rechnung2006[i].Datum:=stringgrid3.Cells[1,i];
v_rechnung2006[i].Typ:=stringgrid3.Cells[2,i];
//v_rechnung2006[i].Betrag:=strtoint(stringgrid3.cells[3,i]);
v_rechnung2006[i].Zahlungsweise:=stringgrid3.Cells[4,i];
end;
//Speicherndialog
if savedialog1.execute then
begin
assignfile(v_dat,savedialog1.Filename);
rewrite(v_dat);
for j:=1 to (Stringgrid1.RowCount) do
begin
rechnung2004:=v_rechnung2004[j];
rechnung2005:=v_rechnung2005[j];
rechnung2006:=v_rechnung2006[j];
write(v_dat,rechnung2004);
write(v_dat,rechnung2005);
write(v_dat,rechnung2006);
end;
closefile(v_dat);
end;
end;


...Allerdings erscheint beim Öffnen mit dem folgenden Quelltext die Fehlermeldung "Versuch hinter dem Dateiende zu lesen"! Woran mag das liegen?...


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:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
procedure TForm1.Oeffnen2Click(Sender: TObject);
var rechnung2004,rechnung2005,rechnung2006: t_rechnung;
    i,j:integer;

begin
if opendialog1.execute then
begin
assignfile(v_dat,opendialog1.Filename);
reset(v_dat);

stringgrid1.RowCount:=filesize(v_dat);

for i:=1 to stringgrid1.RowCount do
begin
read(v_dat,rechnung2004);
read(v_dat,rechnung2005);
read(v_dat,rechnung2006);
v_rechnung2004[i]:=rechnung2004;
v_rechnung2005[i]:=rechnung2005;
v_rechnung2006[i]:=rechnung2006;
end;
closefile(v_dat);
end;
//Daten ins StringGrid schreiben
for j:=1 to stringgrid1.RowCount do
begin
stringgrid1.cells[1,j]:=v_rechnung2004[j].Datum;
stringgrid1.cells[2,j]:=v_rechnung2004[j].Typ;
//stringgrid1.cells[3,j]:=inttostr(v_rechnung2004[j].Betrag);
stringgrid1.cells[4,j]:=v_rechnung2004[j].Zahlungsweise;
stringgrid2.cells[1,j]:=v_rechnung2005[j].Datum;
stringgrid2.cells[2,j]:=v_rechnung2005[j].Typ;
//stringgrid2.cells[3,j]:=inttostr(v_rechnung2005[j].Betrag);
stringgrid2.cells[4,j]:=v_rechnung2005[j].Zahlungsweise;
stringgrid3.cells[1,j]:=v_rechnung2006[j].Datum;
stringgrid3.cells[2,j]:=v_rechnung2006[j].Typ;
//stringgrid3.cells[3,j]:=inttostr(v_rechnung2006[j].Betrag);
stringgrid3.cells[4,j]:=v_rechnung2006[j].Zahlungsweise;
end;
end


Ich bitte euch ujm Hilfe. Ich möchte nicht noch einaml die ganze Nacht durchsitzen und rätseln:) Jetzt seid ihr gefragt mit neuen Ideen:)

Moderiert von user profile iconChristian S.: I- durch Delphi-Tags ersetzt
Moderiert von user profile iconraziel: Topic aus Delphi Language (Object-Pascal) / CLX verschoben am Do 02.03.2006 um 21:03


Sinspin - Do 02.03.06 20:42

bitte mach als erstes mal aus dem einfach text delphi quelltext. dann kann ich das ganze besser lesen. das geht in dem du
unter "bereiche" oberhalb des textfeldes delphi wählst, den cursor vor deinen quelltext stellst, und "+" clickst, dann gehts du hinter deinen quelltext und clickst wieder "+".

dann fällt mir auf das du hinter rewrite und reset als zweiten parameter immer "1" angeben musst! die record größe sollte immer angegeben werden. das führt häufig zu problemen das das in pascal/delphi so dumm gelößt ist.


Sinspin - Do 02.03.06 20:56

fein!

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
if opendialog1.execute then
begin
assignfile(v_dat,opendialog1.Filename);
reset(v_dat);

stringgrid1.RowCount:=filesize(v_dat);

for i:=1 to stringgrid1.RowCount do
begin
read(v_dat,rechnung2004);
read(v_dat,rechnung2005);
read(v_dat,rechnung2006);
v_rechnung2004[i]:=rechnung2004;
v_rechnung2005[i]:=rechnung2005;
v_rechnung2006[i]:=rechnung2006;
end;
closefile(v_dat);


dein fehler ist die zeile:
stringgrid1.RowCount:=filesize(v_dat);

das muss lauten
stringgrid1.RowCount:=filesize(v_dat) div 3;

denn du verteilst deine daten ja auf drei tabellen und nicht auf eine!
es werden ja auch drei einträge für je eine füllung einer zeile von stringgrid1, stringgrid2, stringgrid3 verwendet.
wo setzt du eigentlich die größen der anderen beiden (stringgrid2, stringgrid3)?


addlehead - Fr 03.03.06 04:12

Ich habe bis jetzt geknobelt! Wie kann ich für jedes StringGrid 1-3 die Eigenschaft "rowcount" speichern und diese abrufen beim Öffnen, sodass mein StringGrid beim Öffnen so viel Zeilen bereit stellt, wie Daten vorhanden sind? Mit filesize kann ich das ja wohl schlecht machen, oder? Muss ich den Wert von "rowcount" evtl. in meinen arrays speichern und dann auslesen?
Nochmal: Mein Ziel ist es, in einer Datei die Werte von 3 StringGrids eines Formulars zu speichern und diese Werte genau so auszulesen, wie sie gespeichert sind.
Mein Quelltext hat sich verändert. Ich wollte aber nicht gleich alles reinhauen, um nicht alles zuzumüllen hier...Ich kann nur sagen, dass sich an dem Problem noch nichts effektives geändert hat.
Das Hauptproblem liegt sicherlich beim Öffnen. Ich weis nicht, wie ich jedem StringGrid seine alten Daten zuweisen kann!


Logikmensch - Fr 03.03.06 11:10

Hallo,

zum Speichern von beliebig vielen Stringgrids in nur eine Datei kannst Du auch folgende Routinen verwenden:


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:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
function WriteStringGridToFileStream(grid:TStringGrid; var f:TFileStream):boolean;
var
  xsize,ysize,x,y,len:integer;
  s:string;
begin
  result:=false;
  ysize:=grid.RowCount;
  xsize:=grid.ColCount;
  //Zuerst speichern der Abmessungen des Grids:
  if (f.Write(ysize,sizeof(ysize))=sizeof(ysize)) and
    (f.Write(xsize,sizeof(xsize))=sizeof(xsize)) then begin
    for y:=0 to grid.RowCount-1 do
      for x:=0 to grid.ColCount-1 do begin
        s:=grid.cells[x,y];
        len:=length(s);
        if (f.write(len,sizeof(len))<>sizeof(len)) or
          (f.Write(s[1],length(s))<>length(s)) then break;
      end{for}
    result:=true;
  end{if}
end;

function ReadStringGridFromFileStream(grid:TStringGrid; var f:TFileStream):boolean;
var
  xsize,ysize,x,y,len:integer;
  s:string;
begin
  result:=false;
  if (f.Read(ysize,sizeof(ysize))=sizeof(ysize)) and
    (f.Read(xsize,sizeof(xsize))=sizeof(xsize)) then begin
    grid.RowCount:=ysize;
    grid.ColCount:=xsize;
    for y:=0 to grid.RowCount-1 do
      for x:=0 to grid.ColCount-1 do begin
        if f.Read(len,sizeof(len))=sizeof(len) then begin
          setlength(s,len);
          if f.Read(s[1],len)=len then grid.Cells[x,y]:=s
            else exit;
        end
          else exit;
      end{for}
    result:=true;
  end{if}
end;

procedure TForm1.WriteStringGridsToFile(const fname:string);
var
  fs:TFileStream;
begin
  fs:=TFileStream.Create(fname,fmCreate);
  if writestringgridtofilestream(StringGrid1,fs) then showmessage('ok')
    else showmessage('Schreibfehler!');
  fs.Free;
end;

procedure TForm1.ReadStringGridsFromFile(const fname:string);
var
  fs:TFileStream;
begin
  fs:=TFileStream.Create(fname,fmOpenRead);
  fs.Position:=0;
  if readstringgridfromfilestream(StringGrid1,fs) then showmessage('ok')
    else showmessage('Lesefehler!');
  fs.Free;
end;


Viel Erfolg!


damadmax - Fr 03.03.06 12:48

ich habe es so gelöst...
TStringGrid um folgende funktionen erweitert:


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:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
procedure TmyStringGrid.LoadCSV(aFilename: String);
var
  f : TStrings;
  idx : Integer;
begin
  if fileexists(aFilename) then begin
    f := TStringList.Create;
    try
      f.LoadFromFile(aFilename);
      RowCount := f.Count;
      if RowCount > 0 then
        with TStringList.Create do begin
          CommaText := f[0];
          ColCount := Count;
        end;
      for idx := 0 to RowCount - 1 do begin
        Rows[idx].CommaText := f[idx];
      end;
    finally
      f.Free;
    end;
  end;
end;

procedure TmyStringGrid.SaveCSV(aFilename: String);
var
  f : TStrings;
  idx : integer;
begin
  f := TStringList.Create;
  try
    for idx := 0 to RowCount - 1 do begin
      f.Add(Rows[idx].CommaText);
    end;
    f.SaveToFile(aFilename);
  finally
    f.Free;
  end;
end;


addlehead - Fr 03.03.06 18:29

Danke für eure Hilfe. Ich habe mal Code aus einem alten Thread kopiert. Den habe ich implementiert und es funktioniert auch. Allerdings kann ich nur ein StringGrid speichern. Kann mir jemand verraten anhand des unten stehenden codes, wie ich damit mehrere StringGrids speichern/öffnen kann? Das habe ich bei euren 2 obigen Varianten schon nicht gerafft:(
Würde ich 3 mal die SpeichernFunktion ausführen, dann überschreibt er ja das vorige und kann somit nur die daten des dritten stringgrids auch wieder öffnen.

Delphi-Quelltext
1:
2:
3:
gridspeichern(StringGrid1,'c:\test.txt');
gridspeichern(StringGrid2,'c:\test.txt');
gridspeichern(StringGrid3,'c:\test.txt');



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:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
// Hiermit können StringGrids gespeichert und geladen werden,  
// wobei Inhalt und Form von einem anderweitig gespeicherten  
// Grid in das aktuelle Grid geholt werden können.  
// Siehe auch Stringgrids umklappen  
// Getestet mit D4 unter Win98  
procedure gridspeichern(grd:TStringGrid;Datei:string);  
var  
  sl:TStringlist;  
  x,y:integer;  
begin  
  sl:=TStringlist.create;  
  sl.add(inttostr(grd.colcount));  
  sl.add(inttostr(grd.rowcount));  
  for x:=0 to grd.ColCount-1 do  
    for y:=0 to grd.RowCount-1 do  
      sl.add(grd.cells[x,y]);  
    for x:=0 to grd.ColCount-1 do  
      sl.add(inttostr(grd.ColWidths[x]));  
    for x:=0 to grd.RowCount-1 do  
      sl.add(inttostr(grd.RowHeights[x]));  
    sl.add(inttostr(grd.clientwidth));  
    sl.add(inttostr(grd.clientheight));  
    sl.add(inttostr(ord(grd.ScrollBars)));  
    sl.savetofile(datei);  
    sl.free;  
end;  
procedure gridladen(grd:TStringGrid;Datei:string;angleichen:boolean);  
var  
  sl:TStringlist;  
  x,y,z:integer;  
begin  
  sl:=TStringlist.create;  
  sl.loadfromfile(datei);  
  grd.colcount:=strtoint(sl.strings[0]);  
  grd.rowcount:=strtoint(sl.strings[1]);  
  z:=2;  
  for x:=0 to grd.ColCount-1 do  
    for y:=0 to grd.RowCount-1 do  
    begin  
      grd.cells[x,y]:=sl.strings[z];  
      inc(z);  
    end;  
    if angleichen then  
    begin  
    for x:=0 to grd.ColCount-1 do  
    begin  
      grd.ColWidths[x]:=strtoint(sl.strings[z]);  
      inc(z);  
    end;  
    for x:=0 to grd.RowCount-1 do  
    begin  
      grd.RowHeights[x]:=strtoint(sl.strings[z]);  
      inc(z);  
    end;  
    grd.clientwidth:=strtoint(sl.strings[z]);  
    grd.clientheight:=strtoint(sl.strings[z+1]);  
    grd.ScrollBars:=TScrollStyle(strtoint(sl.strings[z+2]));  
    end;  
    sl.free;  
end;  

 
procedure TForm1.Button1Click(Sender: TObject);  
begin  
  gridspeichern(StringGrid1,'c:\test.grd');  
end;  
procedure TForm1.Button2Click(Sender: TObject);  
begin  
  gridladen(StringGrid1,'d:\test2.grd',true);  
end;


damadmax - So 05.03.06 19:00

der einfachheit wegen würd ich drei dateien nehmen...

oder du schreibst die stringgrids abschnittsweise rein und stellst jedem einen eindeutigen string z.b. '[STRINGGRID1]' voran der angibt woher der folgende abschnitt stammt


Logikmensch - Do 09.03.06 10:51

Hallo addlehead!

meine Variante ist (ohne jetzt die anderen Vorschläge abwerten zu wollen), in der Lage, mehrere StringGrids in eine Datei zu packen. Vielleicht wäre es nicht unklug, so manche Beiträge auch mal zu lesen. ;-)

Beispiel:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
procedure TForm1.WriteStringGridsToFile(const fname:string);  
var  
  fs:TFileStream;  
begin  
  fs:=TFileStream.Create(fname,fmCreate);  
  if writestringgridtofilestream(StringGrid1,fs) and
    writestringgridtofilestream(StringGrid2,fs)
 then showmessage('ok')  
    else showmessage('Schreibfehler!');  
  fs.Free;  
end;  
 
procedure TForm1.ReadStringGridsFromFile(const fname:string);  
var  
  fs:TFileStream;  
begin  
  fs:=TFileStream.Create(fname,fmOpenRead);  
  fs.Position:=0;  
  if readstringgridfromfilestream(StringGrid1,fs) and
    readstringgridfromfilestream(StringGrid2,fs)
 then showmessage('ok')  
    else showmessage('Lesefehler!');  
  fs.Free;  
end;


Liebe Grüße,

Claus.


damadmax - Do 09.03.06 23:45

Zitat:
Vielleicht wäre es nicht unklug, so manche Beiträge auch mal zu lesen.


Lesen? Wer kann lesen? Ich nicht! :) :) :)