Delphi-PRAXiS
Seite 2 von 5     12 34     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi kontinuierlichen Messdaten speichern (https://www.delphipraxis.net/104894-kontinuierlichen-messdaten-speichern.html)

Oracle 12. Dez 2007 14:25

Re: kontinuierlichen Messdaten speichern
 
Ein lesbares Format zu erzeugen, habe ich aus der Sicht noch überhaupt nicht betrachtet. Aber du hast sicher nicht unrecht, wenn du sagst dass die Daten damit auch noch lesbar sind, wenn es die Software nicht mehr gibt. Mit XML habe ich mich bisher aber noch gar nicht auseinander gesetzt.

Naja und nicht mal 2 MB am Tag ist bei der bisherigen Variante richtig.
Allerdings habe ich 16 Temperaturwerte pro Sekunde auszulesen, was die Menge dann schon wieder etwas aufbläht. Und auch wenn Festplatten heute riesig sind, finde ich es trotzdem nicht gut wenn man verschwenderisch mit dem Platz umgeht.

himitsu 12. Dez 2007 14:44

Re: kontinuierlichen Messdaten speichern
 
erzeugst für die 16 Temperaturwerte verschiene Dateien, oder wäre für dich alles in einer lieber?

Wegen der Lesbarkeit:
Wenn das Dateiformat ausreichend dokumentiert ist, dann kann das immer ausgelesen werden (solange es passede Computer gibt).

Jelly 12. Dez 2007 14:51

Re: kontinuierlichen Messdaten speichern
 
Ich denke, wir bewegen uns noch in einer Bandbreite, wo man sicherlich die ganzen Messdaten bequem in einer Datenbank ablegen kann. Damit wird die Auswertung später wesentlich leichter.

Wenn ich das richtig verstehe: Du hast 16 Temperaturfühler. Jeder eine Messung/sec, und ein Messzeitraum von max. 7 Tagen... Dann komme ich auf weniger als 10 Millionen Messwerte/Woche. Das schafft jedes auf dem Markt befindliche Datenbanksystem locker... Und wenns mal eng wird, so würde ich jedes Speichern in einem getrennten Thread auslagern, damit ja auch kein Messwert verloren geht... Die Tabellen indizieren würde ich nicht. Erst nach den Messungen würde ich entsprechende Indizes auf die Spalten hauen.

DerDan 12. Dez 2007 14:56

Re: kontinuierlichen Messdaten speichern
 
Ich finde die Idee,

die Daten im Klartext abzuspeichern am besten.
ich würde pro Zeile eine Messzeitpunkt mit allen Werten in eine datei schreiben.
Auch würde ich die Daten alle 10min oder jede Stunde in eine neue Datei speichern.
Und falls diese Klartext Dateien zu groß werden, würde ich die packen (Zip).
denn besser als mit zip bekommt es kein Binärformat hin.

StarOffice speichert seine Dateien auch so ähnlich.
(Inhalt eines Docs in mehrere XML Dateien und diese dann zusammen packen und speichern)


mfg

DerDan

Oracle 12. Dez 2007 15:23

Re: kontinuierlichen Messdaten speichern
 
Also eine Datei für alle Messfühler halte ich am Sinnvollsten. Woher soll der Kunde nachher sonst wissen welche Datei er öffnen soll.

Oracle 12. Dez 2007 15:43

Re: kontinuierlichen Messdaten speichern
 
Was mir jetzt noch Probleme bereitet:

Wenn ich nun kontinuierlich Daten in meine Datei schreibe, und irgendwann nach einer gewissen Zeit damit fertig bin, woher weiß ich dann wieviele Datensätze diese enthält.
Anders gefragt: Wie lese ich die Datei wieder aus, ohne zu wissen wieviele Schleifendurchläufe ich machen muss, bis ich alle Datensätze habe?

Nikolas 12. Dez 2007 15:53

Re: kontinuierlichen Messdaten speichern
 
Wenn es eine normale textdatei ist, musst du mal nach EOF suchen (End Of File).
Also grob
Delphi-Quellcode:
öffnen(datei);
while (not EOF(datei))
auslesen(datei)
end;
Alternativ weisst du wie groß ein Datensatz ist und du weisst, wie groß die Datei ist. Daran solltest du die Anzahl der Werte ausrechnen können.

DeddyH 12. Dez 2007 15:56

Re: kontinuierlichen Messdaten speichern
 
Bei einer typisierten Datei kannst Du nach dem Öffnen FileSize() erfragen.

himitsu 12. Dez 2007 16:03

Re: kontinuierlichen Messdaten speichern
 
@DeddyH:
aber nur wenn du mit einer festen Datenblockgröße arbeitest

wenn man jetzt hier die Zeit nur sporatisch einfügt, dann ist die Blockgröße nicht mehr fest.



Also du kannst
* entwerder vorm Einlesen die Datei durchgehen und zählen
und dann nochmal alles auslesen und behandeln
* einfach bis zum Dateiende (oder einem Fehler) einlesen
* wärend die datei geschrieben wird mitzählen und dieses dann in einem Header (Dateianfang) nachtragen oder einen Fotter (Daeiende) anhängen
vorm einlesen wird dann nur noch der Heder/Fotter gelesen.


Allgemein solltest du bei den kurzen Messabständen die Datei/Datenbank nicht für jeden Messwert neu öffnen.

hier mal 'ne binäre Variante mit Temperatur als Word gespeichert und direkt über die WinAPI (alles andere wie z.B. TFileStream geht im Grunde auch über die WinAPI).
Außerdem in süßen Klassen und es wird nur alle mindestens 60 Sekunden die Zeit mitgespeichert:

Code:
[Word=$FFFF][Double] // Zeit
[Word] // Temperatur
[Word] // Temperatur
...
[Word=$FFFF][Double] // Zeit
[Word] // Temperatur
Delphi-Quellcode:
Uses Windows, SysUtils;

Type TFileSave = Class
    hFile: THandle;
    Time: LongWord;
    Constructor Create; //Override;
    Destructor Destroy; Override;
  Public
    Function Open(Const FileName: String; CreateNew: Boolean = False): Boolean;
    Function Save(Temp: Single): Boolean;
    Function Close: Boolean;
  End;

  TFileLoad = Class
    hFile: THandle;
    Time: TDateTime;
    Constructor Create; //Override;
    Destructor Destroy; Override;
  Public
    Function Open(Const FileName: String): Boolean;
    Function Load(Out Time: TDateTime; Out Temp: Single): Boolean;
    Function Close: Boolean;
  End;

Constructor TFileSave.Create;
  Begin
    Inherited;
    hFile := INVALID_HANDLE_VALUE;
  End;

Destructor TFileSave.Destroy;
  Begin
    CloseHandle(hFile);
    Inherited;
  End;

Function TFileSave.Open(Const FileName: String; CreateNew: Boolean = False): Boolean;
  Var CD: LongWord;

  Begin
    CloseHandle(hFile);
    If CreateNew Then CD := CREATE_ALWAYS Else CD := OPEN_ALWAYS;
    hFile := CreateFile(PChar(FileName), GENERIC_WRITE, FILE_SHARE_READ,
      nil, CD, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN, 0);
    SetFilePointer(hFile, 0, nil, FILE_END);
    Time  := GetTickCount - 60000;
    Result := hFile <> INVALID_HANDLE_VALUE;
  End;

Function TFileSave.Save(Temp: Single): Boolean;
  Var D: TDateTime;
    W: Word;
    W2: LongWord;

  Begin
    Result := True;
    If GetTickCount >= Time + 60000 Then Begin
      W     := $FFFFFFFF;
      D     := Now;
      Result := Result and WriteFile(hFile, W, SizeOf(W), W2, nil) and (W2 = SizeOf(W));
      Result := Result and WriteFile(hFile, D, SizeOf(D), W2, nil) and (W2 = SizeOf(D));
      Time  := GetTickCount;
    End;
    W := Round(Temp * 100);
    If W = $FFFF Then W := $FFFE; // Spezialwert als Temperatur verhindern
    Result := Result and WriteFile(hFile, W, SizeOf(W), W2, nil) and (W2 = SizeOf(D));
  End;

Function TFileSave.Close: Boolean;
  Begin
    Result := CloseHandle(hFile);
  End;

Constructor TFileLoad.Create;
  Begin
    hFile := INVALID_HANDLE_VALUE;
  End;

Destructor TFileLoad.Destroy;
  Begin
    CloseHandle(hFile);
  End;

Function TFileLoad.Open(Const FileName: String): Boolean;
  Begin
    CloseHandle(hFile);
    Time  := 0;
    hFile := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ,
      nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN, 0);
    Result := hFile <> INVALID_HANDLE_VALUE;
  End;

Function TFileLoad.Load(Out Time: TDateTime; Out Temp: Single): Boolean;
  Var D: TDateTime;
    W: Word;
    W2: LongWord;

  Begin
    Result := ReadFile(hFile, W, SizeOf(W), W2, nil) and (W2 = SizeOf(W));
    If Result Then
      If W = $FFFFFFFF Then Begin
        Result := ReadFile(hFile, D, SizeOf(D), W2, nil) and (W2 = SizeOf(D));
        If Result Then Begin
          Result := Load(Time, Temp);
          Time  := D;
        End;
      End Else Begin
        Time := Time + 1/24/60/60;
        Temp := W / 100;
      End
  End;

Function TFileLoad.Close: Boolean;
  Begin
    Result := CloseHandle(hFile);
  End;
Delphi-Quellcode:
Uses Windows, SysUtils, Unit3;

Var FS: TFileSave;
  FL: TFileLoad;
  Temp: Single;
  Time: TDateTime;
  S: String;

Begin
  FS := TFileSave.Create;
  If not FS.Open('Project3.dat') Then
    Raise Exception.Create('TFileSave - create/open file');

// {wiederholen}
//   Temp := Wert_holen;
//   FS.Save(Temp);
// {/wiederholen}

  {test}
    FS.Save(12.3);
    Sleep(1000);
    FS.Save(4.56);
    Sleep(1000);
    FS.Save(78.9);
  {/test}

  FS.Close;



  FL := TFileLoad.Create;
  If not FL.Open('Project3.dat') Then
    Raise Exception.Create('TFileLoad - create/open file');

// {wiederholen}
//   FL.Load(Time, Temp);
//   Zeit_ausgeben      := Time;
//   Temperatur_ausgeben := Temp;
// {/wiederholen}

  {test}
    While FL.Load(Time, Temp) do Begin
      S := DateTimeToStr(Time) + ' = ' + FloatToStr(Temp);
      MessageBox(0, PChar(S), '', 0);
    End;
  {/test}

  FL.Close;
End;
Dieses könnte man jetzt noch um mehr TempWert erweitern (eventuell sogar mit einer dynamischen Anzahl) und falls sich das Messintervall mal ändern könnte, dann sollte man es auch noch mit in der Datei speichern.

Wertebereich: 0.00 <= Temp <= 655.36

und falls man Word durch SmallInt (für Temp) ersetzt, dann -327.68 <= Temp <= 327.67

DeddyH 12. Dez 2007 16:39

Re: kontinuierlichen Messdaten speichern
 
Zitat:

Zitat von himitsu
...wenn man jetzt hier die Zeit nur sporatisch einfügt, dann ist die Blockgröße nicht mehr fest.

Dann ist das aber auch keine typisierte Datei ;)


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:41 Uhr.
Seite 2 von 5     12 34     Letzte »    

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz