Entwickler-Ecke

Dateizugriff - Unterschiedl. Messungen untereinander in eine Datei speicher


Blizzi - Do 09.09.10 11:33
Titel: Unterschiedl. Messungen untereinander in eine Datei speicher
Hallo,
kann mir jemand sagen, wie es möglich ist Messergebnisse in eine Textdatei zu speichern ?
Das Programm ist so aufgebaut, dass mit einem Button Messergebnisse mittels .DLL geladen werden und mit einem "Speichern-Button" anschließend auch mit zusätzlichen Eingaben in eine Textdatei abgespeichert werden können.
Es soll jedoch möglich sein, dass durch mehrmaliges Erfassen der Messwerte diese untereinander aufgelistet werden. Bisher wird durch erneutes Drücken des "Messwerte erfassen-Taste" die vorige Messreihe direkt überschrieben, sodass in der Textdatei immer nur eine Messung dargestellt wird.

Beispiel:

1. Messung:

xyz
..............

2. Messung:

abc
..............

3. Messung:
.
.
.
.


Ich hoffe ich konnte mein Problem einigermaßen rüberbringen.
Würde mich sehr über Hilfe freuen.


Moderiert von user profile iconNarses: Topic aus Windows API verschoben am Do 09.09.2010 um 11:48


elundril - Do 09.09.10 11:35

Hallo und :welcome: im DF!

Möglichkeit A: In ne Stringlist laden und unten anfügen.
Möglichkeit B: Mit TFile arbeiten.
Möglichkeit C: Mit Streams arbeiten.

in der Forensuche und bei google sollte man damit schon recht viel finden.

lg elundril


Blizzi - Do 09.09.10 11:44

Ui danke für die schnelle Antwort und danke :)
Bin quasi Quereinsteiger.
Habe es jetzt mit ner Memo probiert und sieht schon gar nicht schlecht aus.
Werde mir aber deine Möglichkeiten auch nochmal anschauen, da mit meiner jetzigen Lösung nur jede 1 Sekunde ein Messwert aufgenommen werden kann. Die Übergabe scheint etwas langsam zu sein *g*


zuma - Do 09.09.10 11:51

Zeig doch mal etwas von deinem Code, eine Messung pro Sekunde kommt mir komisch vor.
wenn du bei programmstart die bisherigen Messergebnisse in eine Stringlist lädst, deine Messungen bei jedem klick ins memo schreibst und erst beim speichernclick den inhalt des Memo's an die Stringlist anhängst, sollte doch die ausführungszeit deiner Messungen nicht vom speichern beeinflußt werden ?


Critter - Do 09.09.10 12:00

Hi,
user profile iconBlizzi hat folgendes geschrieben Zum zitierten Posting springen:
Habe es jetzt mit ner Memo probiert und sieht schon gar nicht schlecht aus.


das wurde dann Variante A von user profile iconelundril antspechen, nur dass du noch eine Menge Visuellen Ballast mit schleppst.

Der dürfte auch für dein Geschwindigkeitsproblem verantwortlich sein, wenn alles was in die Datei soll erst Visualisiert wird frisst das Unmengen an Zeit. Wenn du also mehr als eine Änderung durchführst solltest du das deinen Komponenten mitteilen, die meisten bieten hierfür die Methoden BeginUpdate und EndUpdate bei einem Memo sollte das also so aussehen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
  Memo1.Lines.BeginUpdate;
  Try
    {Mache ganz viel mit deinem Memo}
  Finally
    Memo1.Lines.EndUpdate; // Erst jetzt wird neu gezeichnet
  End;


Wobei du dieses Beispiel auch als Beispiel für die von user profile iconelundril erwähnten Stringlist ansehen kannst, denn Memo.Lines ist nichts anderes als eine solche Liste.

critter


Blizzi - Do 09.09.10 12:00

ah :)
Bisher habe ich es wie folgt.. sieht bissle wüst aus :)


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:
procedure TFormPPS.FormCreate(Sender: TObject);
begin
    StartDevice; //Stellt Verbindung zum externen Gerät her
end;

procedure TFormPPS.ButtonMessungClick(Sender: TObject);
  var p:pointer;
  i:integer;
  s1:string;
  s2:string;
  s3:string;
  s4:string;
    begin
        p:=@DataBuffer;
        ReadData(p);
        s1:='';
        for i:=2 to 2 do s1:=s1 +inttostr(DataBuffer[i])+chr(9);
        LabelMenge2.Caption:='';
        PanelMenge.Caption:=s1;
        s2:='';
        for i:=3 to 3 do s2:=s2 +inttostr(DataBuffer[i])+chr(9);
        LabelTemp2.Caption:='';
        PanelTemp.Caption:=s2;
        s3:='';
        for i:=4 to 4 do s3:=s3 +inttostr(DataBuffer[i])+chr(9);
        LabelDruck2.Caption:='';
        PanelDruck.Caption:=s3;
        s4:='';
        for i:=5 to 5 do s4:=s4 +inttostr(DataBuffer[i])+chr(9);
        LabelSaug2.Caption:='';
        PanelSaug.Caption:=s4;
 end;

procedure TFormPPS.ButtonSpeichernClick(Sender: TObject);

    begin
      SaveDialog.Execute;
        try
            FormMemo.Memo.Lines.Add(...........); // Eingabe in Edit
            FormMemo.Memo.Lines.Add(...........); // Eingabe in Edit
            FormMemo.Memo.Lines.Add(...........); // Eingabe in Edit
            FormMemo.Memo.Lines.Add(...........); // Eingabe in Edit
            FormMemo.Memo.Lines.Add(...........); // Eingabe in Edit
            FormMemo.Memo.Lines.Add(...........); // Eingabe in Edit
            FormMemo.Memo.Lines.Add(...........); // Eingabe in Edit
            FormMemo.Memo.Lines.Add(...........); // Eingabe in Edit
            FormMemo.Memo.Lines.Add('------------------------------------------------');
            FormMemo.Memo.Lines.Add(..........................); // Beschreibungen für Spalten
            FormMemo.Memo.Lines.Add(PanelMenge.Caption+chr(9)+PanelTemp.Caption+chr(9)+PanelDruck.Caption+chr(9)+PanelSaug.Caption);
            FormMemo.Memo.Lines.SaveToFile(SaveDialog.FileName);

        finally
      end;
    end;


Mitm oben Teil nehme ich die aktuellen Messwerte auf und dann kommt das Speichern, wobei da zusätzlich noch Eingaben, welche vom Programmbenutzer noch hinzugefügt worden sind, mit abgespeichert werden ( Die Punkte in der Klammer sind dann die Eingaben ).

Bestimmt ist das mal mega durcheinander und total unübersichtlich :)

Moderiert von user profile iconNarses: Code- durch Delphi-Tags ersetzt


Critter - Do 09.09.10 12:04

Hi,
user profile iconBlizzi hat folgendes geschrieben Zum zitierten Posting springen:
sieht bissle wüst aus :)

wenn du Delphi- anstelle von Code-Tags verwendest wird es zumindest hier im Forum ein wenig übersichtlicher ;).

Auf jeden Fall solltest du ButtonSpeichernClick um BeginUpdate und Endupdate erweitern, dann kann man weiter gucken ;).

critter


Blizzi - Do 09.09.10 12:11

Habe die Memo auf in nem neuen Form erstellt und bei Visible:=false eingestellt..
Mit dem BeginUpdate und EndUpdate hat sich leider nichts an der Geschwindigkeit verändert ^^


platzwart - Do 09.09.10 12:13

Ist nicht eher das ReadData(p); so langsam?


Blizzi - Do 09.09.10 12:15

Also wenn das externe Gerät via USB verbunden ist und ich Messergebnisse erfasse zeigt er mir die Werte sofort grafisch an. Aktualisiert also immer die Anzeige.. aber das Hinterlegen macht da wohl nicht so schnell mit.


elundril - Do 09.09.10 12:17

user profile iconBlizzi hat folgendes geschrieben Zum zitierten Posting springen:
Habe die Memo auf in nem neuen Form erstellt und bei Visible:=false eingestellt.


Das is böse, böse, böse ;) Visuelle Komponenten sind zum Anzeigen da, deswegen heißen sie "Visuelle Komponenten". Braucht man keine Anzeige gibt es ja noch die nicht-visuellen, in deinem Fall die TStringList. ;)

Zur aktualisierungsgeschwindigkeit: Manche Geräte liefern zb. nur einmal in der Sekunde Daten. Kommt halt auf gerät an. Und wenn man das so haben will/das so gewollt ist, gehts auch mit schnellerem code nicht schneller. ;)

lg elundril


Blizzi - Do 09.09.10 12:23

Ach das Gerät könnte 100 Messwerte in 1s raushauen, wenn an es möchte. Das ist nicht das Problem.
Ich halte ja auch nur für den Augenblick mit nem Tastendruck einen Wert fest. Teste es im Moment auch nur, wobei das Gerät nicht angschlossen ist. Dabei übergibt er mir einfach 0en, da das Eingangssignal ja 0 volt beträgt.
Das StringListe hatte ich zu anfang. Nur dabei hat er mir bei jedem Drücken die vorigen Messwerte immer überschrieben und sie nicht wie gewollt darunter gesetzt.


elundril - Do 09.09.10 12:35

Und ihr Stichwort für die Suche heute lautet: StringList.Items.Add(); ;)

lg elundril


Blizzi - Do 09.09.10 13:42

Ok gut.. habe jetzt herausgefunden, dass man das zuvor "Abgelegte" wieder aufrufen muss, damit die nächste Messung darunter platziert wird.
Habe es mit:

Liste.LoadFromFile(SaveDialog.Filename);

erstmal probiert.
Dies funktioniert aber nur, wenn bereits eine Datei existiert und man dann diese Datei überspeichert. Möchte man dann jedoch eine neue Datei anlegen bekomme ich die Meldung, dass keine Datei existieren würde und das Programm schließt sich.

Und auch sonst ordnet er bei mehrmaligem Klicken nicht mehrere Messwerte untereinander.


platzwart - Do 09.09.10 13:49

Liste.LoadFromFile(SaveDialog.Filename);


Dann schau mal, was du da machst... du lädst eine Datei mit dem Dateinamen, der im Speicherndialog angegeben ist?!?


Blizzi - Do 09.09.10 13:56

Wie gesagt bin neu was das Programmieren betrifft und versuche hier Hilfe zu erhalten.
Über diverse Google.Recherchen erhalte ich auch keine Antwort auf mein Problem.
Sonst würde ich hier ja nicht nachfragen.
Aber man wird hier ja eh eher runtergemacht als das man konstruktiv Hilfe erhält.

Mir geht es lediglich darum, wie ich es umsetzen kann, dass mir Messwerte untereinander durch Klicken eines Buttons angeordet werden , was im Anschluss in eine Textdatei abgespeichert werden soll.


zuma - Do 09.09.10 14:07

Ich glaube nicht, das dich hier jemand 'runtermacht'. Einige haben eben eine etwas direkte Art, aber ich sehe hier nur bemühen, dir zu helfen. Also nicht gleich beleidigt sein ;)

dein loadfromfile-problem könntest du lösen, indem du erst nach existiert-datei-frage ala

Delphi-Quelltext
1:
2:
if Fileexits(filename) then
 liste.loadfromfile(filename);

die datei lädst.
ist sie nicht vorhanden, braucht dich das ja nich weiter stören, beim speichern legst du dann ja eine Datei an.
der hinweis mit Savedialog sollte dir wohl aufzeigen, das es neben dem speicherdialog auch einen Öffnendialog (TOpendialog) gibt und du den für das laden der 'alten' messergebnis-datei benutzen solltest


platzwart - Do 09.09.10 14:08

Hier will dich niemand fertig machen, wir helfen dir ja gern ;)

Nur muss man halt nachfragen, ob es einen Grund gibt, aus dem Speicherndialog heraus den Dateinamen zum Öffnen einer Datei zu nehmen. Das schaut einfach etwas seltsam aus...

Nimm lieber einen OpenDialog. Und dann sowas in der Art:


Delphi-Quelltext
1:
2:
3:
4:
If(FileExists(Opendialog.FileName))then
 Liste.LoadFromFile(OpenDialog.Filename)
else
 Liste.Clear;


Blizzi - Do 09.09.10 14:28

Irgendwie reden wir aneinander vorbei.

Ich erklärs nochmal Schritt für Schritt.
Über ein externes Gerät, welches via USB mitm Rechner verbunden ist, sollen Messwerte einer Pumpe aufgenommen werden. Dafür steht bereits eine Software zur Verfügung, welche jedoch nicht den Vorstellungen entspricht die wir haben. Über die .DLL-Dateien des Programms ist es aber möglich eine eigene Applikation zu schreiben. Diese Aufgabe habe ich nun.

In diesem Programm sollen zusätzliche Eingaben (Pumpentyp, Baujahr, Werk.Nr. usw) über die Pumpe möglich sein, sowie das festhalten von Messergebnissen.
Dafür habe ich also einen Button "Messwerte erfassen" eingefügt und eine OnClick-Eigenschaft hinzugefügt.


Delphi-Quelltext
1:
procedure TFormPPS.ButtonMessungClick(Sender: TObject);                    


Damit soll es nun möglich sein Daten in eine StringList zu hinterlegen.
Wenn an einmal klickt sollen die Eingaben über die Pumpe und die Signale der 4 Messeingänge in der StringList aufgezeichnet werden.
Das hat bis hierhin auch alles wunderbar funktioniert.
Es soll aber nicht bei einer Messung bleiben. Es sollen mehrere durchgeführt werden.
Drückt man nun nochmals auf den "Messung erfassen" Button ersetzt er einfach die vorige Messung.
Ich möchte jedoch, dass er sie darunter setzt, ohne die 1. Messung zu verändern und ohne, dass zwischendurch abgespeichert wird.
Aus diesem Grund ist in meinen Augen die OpenDialog-Methode nicht einsetzbar. Es existiert ja noch keine Datei.. nur halt diese StringList.

Erst wenn alle Messungen durchgeführt worden sind die geplant waren, soll doch einen "Messergebnisse speichern" Button das ganze in einer Textdatei abgespeichert werden, wo dann alle Messungen untereinander dargestellt werden.


Hoffe ich konnte es jetzt nochmal besser rüber bringen.
Code bisher:


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:
procedure TFormPPS.ButtonMessungClick(Sender: TObject);
  var p:pointer;

  i:integer;
  s1:string;
  s2:string;
  s3:string;
  s4:string;
    begin
        p:=@DataBuffer;
        ReadData(p);
        s1:='';
        for i:=2 to 2 do s1:=s1 +inttostr(DataBuffer[i])+chr(9);
        LabelMenge2.Caption:='';
        PanelMenge.Caption:=s1;
        s2:='';
        for i:=3 to 3 do s2:=s2 +inttostr(DataBuffer[i])+chr(9);
        LabelTemp2.Caption:='';
        PanelTemp.Caption:=s2;
        s3:='';
        for i:=4 to 4 do s3:=s3 +inttostr(DataBuffer[i])+chr(9);
        LabelDruck2.Caption:='';
        PanelDruck.Caption:=s3;
        s4:='';
        for i:=5 to 5 do s4:=s4 +inttostr(DataBuffer[i])+chr(9);
        LabelSaug2.Caption:='';
        PanelSaug.Caption:=s4;

      Liste := TStringList.Create;

        try
            Liste.Add('Messung:');
            Liste.Add('');
            Liste.Add('Pumpenkennwerte vom Benutzer eingegeben:');
            Liste.Add('');
            Liste.Add(LabelAuftrag.Caption + ' ' + EditAuftrag.Text);
            Liste.Add(LabelPumpe.Caption + ' ' + EditPumpe.text);
            Liste.Add(LabelNr.Caption + ' ' + EditNr.text);
            Liste.Add(LabelBaujahr.Caption + ' ' + EditBaujahr.text);
            Liste.Add(LabelQ.Caption + ' ' + EditQ.text + ' m³/h');
            Liste.Add(LabelH.Caption + ' ' + EditH.text + ' m');
            Liste.Add('------------------------------------------------');
            Liste.Add('CH1 in Volt'+chr(9)+'CH2 in Volt'+chr(9)+'CH3 in Volt'+chr(9)+'CH4 in Volt');
            Liste.Add(PanelMenge.Caption+chr(9)+PanelTemp.Caption+chr(9)+PanelDruck.Caption+chr(9)+PanelSaug.Caption);
            Liste.Add('');
        finally

      end;
 end;


Stundenplan - Do 09.09.10 14:50

Also:
Als erstes im try-Block solltest du Liste.LoadFromFile(Dateiname); ausführen, damit lädst du die Datei Dateiname. In ihr stehen deine vorherigen Messungen drin. Dann fügst du eben deine Zeilen hinzu, und speicherst das ganz wieder unter der Datei Dateiname mithilfe von Liste.SaveToFile(Dateiname);. Den Dateinamen kannst du vorher über einen TOpenDialog oder TSaveDialog eingeben/auswählen lassen. Wie, wurde schon angesprochen.
Jetzt wird an deine Messungs-Textdatei immer die neue Messung angehängt und das ganze gespeichert. Das willst du doch, oder?

Viele Grüße,
Stundenplan.


zuma - Do 09.09.10 14:59

Dein Problem scheint mir eher von der Ablaufsteuerung des Codes bzw. dessen Verständnis zu kommen:

also, bei anzeigen deiner Form benutzt du den Opendialog (oder eben nur per Buttonklick, wenn du nicht immer eine Datei laden willst). Dann läuft das Programm und du kannst alles andere machen (z.b. eben die messungen, Pumpennameneingabe, etc).
bei jeden Messungen-click machst du einen eintrag in deine Stringliste (TStringList oder Memo, wie du magst)

Delphi-Quelltext
1:
Stringliste.add(DeinEintragAlsString);                    

und wenn du speichern klickst, machst du dein saveToFile (z.b. unter verwendung von TSaveDialog).

Mach dir mal klar, wie du deine Aufgabe zeitlich abarbeitest, evtl. wirds dann einfacher verständlich für dich:
Beispiel:
1. Formular öffnen
2. (evtl.) alte Messungen laden ('automatisch oder per Button, Opendialog nutzen)
3. Daten erfassen und zwischenspeichern (Pumpenname in Edit, Messung in Stringlist, etc).
4. Speichern (Savedialog nutzen)
5. Formular schliessen

diese punkte kann man natürlich noch weiter unterteilen (z.b. 2a alte Messungen anzeigen), ich wollte dir nur einen denkanstoss geben


platzwart - Do 09.09.10 15:00

Dann erstell doch 3 Buttons:

1) 'Neu' -> Liste leeren
2) 'Messen' -> Liste füllen
3) 'Speichern' -> Liste speichern


Critter - Do 09.09.10 17:34

Hi,

mal eine ganz verwegene Idee. Du könntest deine Daten auch ganz klassisch "Pascal-Like" ohne die Verwendung irgendwelcher Objekte Speichern, dann musst du auch nichts vorher Laden sondern hängst einfach so an.

Eine Entsprechende Funktion könnte so aussehen:


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:
function TFormPPS.WriteData(aFileName: String): Boolean;
var
  f : TextFile; // Deine TextDatei
begin
  Result := False;
  // Zuerst die Datei öffnen
  AssignFile(f, aFileName); // Dateivariable mit Dateinamen verknüpfen
  if FileExists(aFileName) then
    Append(f) // Datei im "anhängen Modus" öffnen
  else
    Rewrite(f); // Datei im überschreiben Modus öffnen, erstellt die Datei wenn noch nicht existent
  try
    // Und den Inhalt schreiben
    WriteLn(f, '...........'); // Eingabe in Edit
    WriteLn(f, '...........'); // Eingabe in Edit
    WriteLn(f, '...........'); // Eingabe in Edit
    WriteLn(f, '...........'); // Eingabe in Edit
    WriteLn(f, '...........'); // Eingabe in Edit
    WriteLn(f, '...........'); // Eingabe in Edit
    WriteLn(f, '...........'); // Eingabe in Edit
    WriteLn(f, '...........'); // Eingabe in Edit
    WriteLn(f, '------------------------------------------------');
    WriteLn(f, '..........................'); // Beschreibungen für Spalten
    WriteLn(f, PanelMenge.Caption+chr(9)+PanelTemp.Caption+chr(9)+PanelDruck.Caption+chr(9)+PanelSaug.Caption);
    Result := True;
  finally
    CloseFile(f); // Wichtig, die Datei wieder schließen.
  end;
end;


Das ganze ist zwar ziemlich "oldfashoned" sollte aber genau das machen was du willst und auch noch resourcenschonender sein als das ganze Meno-/Stringlist-Zeug. Auch ist es sicher nicht schlecht, für deinen Lernfortschritt wenn du mal an Basics geführt wirst ;). Falls du dieses Prinzip verwenden möchtest habe ich auch eine nette Hausaufgabe für dich ;). Erweitere die Fehlerbehandlung so, das nicht nur ein False (= Irgendwas hat nicht geklappt) dabei heraus kommt, sondern eine Anständige Fehlermeldung, die hinweise darauf gibt, was denn nicht geklappt hat. Zwei Stichworte für unterschiedliche Wege das zu erreichen lauten IORESULT und Exceptions. Ist beides recht interessant finde ich ;). Als weitere Alternative zur Dateiverarbeitung seien hier auch die schon weiter ober erwähnten Streams betont. Auch da lohnt es sich, sich mal ein zu lesen.

critter