| Autor |
Beitrag |
Gausi
      
Beiträge: 8554
Erhaltene Danke: 481
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Fr 17.12.04 13:08
Ich habe vor, eine Art Verwaltungsprogramm zu schreiben. Die Objekte, die ich dabei verwalten möchte, haben in etwa folgende Eigenschaften: Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| bitrate: integer; vbr: boolean; samplerate: integer; dauer:integer; artist: string; titel: string; pfad: string; kommentar: string: [...] |
Davon habe ich mehrere 1000 Stück. Bisher habe ich zum speichern von sowas immer Inifiles verwendet, aber da hatte ich auch nur <100. (Also Anzahl der Objekte speichern, und dann für jedes Objekt eine Section) Geht wunderbar, aber bei 20.000 dürfte das ineffizient werden.
Nächste Idee war, typisierte Dateien zu nehmen. Dann krieg ich aber Probleme erstens mit den dynamischen Elementen (wie z.B. string), und zweitens ist das nicht updatefähig. D.h. wenn ich mein Programm update, und meine Objekte erweitere, muss ich die alten Dateien erst umkonvertieren, oder immer die alten Laderoutinen mit im Quellcode lassen. Halte ich auch für ungut.
Dann kommen die TFilestreams. Aber da bin ich mir grade nicht ganz sicher, wie ich das da mit der Erweiterungsfähigkeit machen soll. Meine Idee ist, für jedes Objekt erst die Gesamtgröße zu speichern. Quelltext 1: 2: 3: 4: 5: 6:
| Dateiaufbau: 4 Bytes Anzahl der Objekte 4 Bytes Größe Objekt1 x Bytes Eigenschaften Objekt1 4 Bytes Größe Objekt2 y Bytes Eigenschaften Objekt2 [...] |
Die einzelnen Eigenschaften sähen dann in der Datei so aus:
Quelltext 1: 2: 3:
| 1. byte: ID 2-5. Byte: Größe 6.-?. Byte: Inhalt. | Beim Lesen kann aus der ID dann die passende Eigenschaft ermittelt werden, und eine unbekannte wird einfach übersprungen. Könnte man mit Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| repeat case ID of 0: objekt.bitrate:=...; 1: objekt.vbr:=...; [...] end; until (objekt zuende gelesen); | machen, aber da habe ich Bedenken was die Effizienz angeht. Es wird ja so z.B. nicht berücksichtigt, dass die einzelnen Eigenschaften in einer bestimmten Reihenfolge gespeichert sind. Gibt es was besseres als diese Möglichkeit?
_________________ We are, we were and will not be.
|
|
MrSaint
      
Beiträge: 1033
Erhaltene Danke: 1
WinXP Pro SP2
Delphi 6 Prof.
|
Verfasst: Fr 17.12.04 13:17
Alles in einer Datenbank speichern? Da kommts nu halt drauf an, ob dein Prog sowas werden soll wie WinAmp irgendwie, was kleines feines, wo man schnell draufhaut und dann läufts, oder was größeres, wo man auch durchaus bereit is mehr zeit zur Installation zu investieren
MrSaint
_________________ "people knew how to write small, efficient programs [...], a skill that has subsequently been lost"
Andrew S. Tanenbaum - Modern Operating Systems
|
|
grayfox
      
Beiträge: 800
win98, winXP
D4 Standard; D6 Personal
|
Verfasst: Fr 17.12.04 13:32
hallo gausi!
leg eine tabelle für deine daten an und trag sie dort ein. somit bist du schon mal von der anzahl der sätze (nahezu) unabhängig, kannst einfach darauf zugreifen und einträge wiederfinden und sie, ohne großartige verrenkungen dabei anstellen zu müssen, auch editieren.
für den anfang reicht paradox vollkommen, auch wenn dir in kürze bestimmt ein SQL-server dafür empfohlen wird
mfg, stefan
|
|
Gausi 
      
Beiträge: 8554
Erhaltene Danke: 481
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Fr 17.12.04 13:50
nun, es soll was kleines, schnelles werden. Also das Programm soll klein und schnell sein und mit WInamp zusammenarbeiten. Bisher habe ich die Dateien auf diversen CDs, und den ganzen Krempel in einer Excel-Tabelle gespeichert, in der ich suchen kann, um dann die entsprechende CD einzulegen usw.
Ich überlege aber zur Zeit ernsthaft, die ganzen CDs auf ein externe Platte zu packen.
Ich möchte also quasi die Daten (und einige mehr) aus der Excel Tabelle übernehmen (kein wirkliches Problem) und diese in meinem Prog anzeigen lassen, so dass ich z.B. bei einem Doppelklick auf ein spezielles Element Winamp starten kann, und das Ding wird abgespielt.
Natürlich wäre eine Datenbank das sinnvollste für sowas, aber geht das mit einer Personal-Version? AFAIK nicht. Also muss ich da ein paar Verrenkungen machen, und mir was eigenes zurechtbasteln. Erstes Problem war das schnelle Speichern und Laden.
Das nächste Problem wird die Anzeige sein mit "Sortieren nach", "Suchen", etc. Aber soweit bin ich noch gar nicht...ich denke da zur Zeit an eine Listview und hoffe, dass ich da 20.000 Einträge gut reinpacken kann, ohne das das Suchen oder Sortieren ungemütlich lange dauert.
_________________ We are, we were and will not be.
|
|
jasocul
      
Beiträge: 6395
Erhaltene Danke: 149
Windows 7 + Windows 10
Sydney Prof + CE
|
Verfasst: Fr 17.12.04 14:15
Halo Gausi,
Wenn ich das richtig gesehen habe, hast du einen festen Record.
Du kannst das ganze, wenn du auf eine DB verzichten willst, auch als "File of Type" machen.
Ist mit ein bisschen Aufwand verbunden, aber durchaus realisierbar.
Beim Programmstart liest du das ganze in eine Liste ein und merkst dir die Datei-Position dazu. Dann kannst du über Seek ziemlich schnell auf den richtigen Record zugreifen.
Oder du liest von vornherein alles ein. Dafür kannst du zum Beispiel eine verkettete Liste nehmen. Ein TTreeView könnte auch eine elegante Lösung sein.
|
|
wulfskin
      
Beiträge: 1349
Erhaltene Danke: 1
Win XP
D5 Pers (SSL), D2005 Pro, C, C#
|
Verfasst: Fr 17.12.04 14:51
Oh, man sollte erst lesen, bevor man antwortet  . Ich würde einfach mal dein Vorschlag ausprobieren. Ich denke, dass mit dem Case sollte die Sache nicht so wahnsinnig verlangsamen!
_________________ Manche antworten um ihren Beitragszähler zu erhöhen, andere um zu Helfen.
Zuletzt bearbeitet von wulfskin am Fr 17.12.04 14:53, insgesamt 1-mal bearbeitet
|
|
Gausi 
      
Beiträge: 8554
Erhaltene Danke: 481
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Fr 17.12.04 14:52
So richtig fest ist mein Record ja nicht, da ich mich eigentlich nicht auf eine feste Stringlänge begrenzen will (z.B. bei Artist auf 30 wie im ID3v1-Tag), sondern beliebige Strings zulassen möchte. Mach ich den String länger (z.B. auf 60), dann habe ich für Artist, Album und Titel ziemlich oft locker zusammen 90 Bytes verschenkt, macht bei 20.000 Files ungefähr 2 MB. Das ist mir zuviel. Also scheidet "File of mp3files" schonmal aus.
Wie ich die geladenen Daten hinterher verwalte (Liste/Array) und wie ich die Anzeige realisiere (Listview mit Spalten für Artist, Titel, etc. oder einen (variablen) Treeview mit unterschiedlicher Knoten-ebenen-ordnung) ist noch eine andere Frage (komme ich evtl. in einem anderen Thread drauf zurück). Es geht mir im Moment erstmal darum, wie ich das vernünftig abspeichern und wieder laden kann.
_________________ We are, we were and will not be.
|
|
jasocul
      
Beiträge: 6395
Erhaltene Danke: 149
Windows 7 + Windows 10
Sydney Prof + CE
|
Verfasst: Fr 17.12.04 16:05
Wenn du eine Datenbank nimmst hast du aber auch eine feste Stringlänge. Wie das gespeichert wird hängt aber auch davon ab, wie die DB das verwaltet. Ich bin mir sicher, dass du mit einer DB mehr Speicherplatz Speicherplatz verbrauchst.
Die einzige Idee, die ich noch hätte (ohne DB) sind INI-Dateien.
Anmerkung: Was sind in heutigen Zeiten noch 2 MB ?
Ein paar Urlaubsbilder verbrauchen da schon mehr Platz.
|
|
wulfskin
      
Beiträge: 1349
Erhaltene Danke: 1
Win XP
D5 Pers (SSL), D2005 Pro, C, C#
|
Verfasst: Fr 17.12.04 16:49
Hallo Gausi,
ich denke du solltest wirklich einen Stream nehmen, aber ich würde das Format etwas vereinfachen: Quelltext 1: 2: 3: 4:
| Identifikation (X Bytes) Version (Integer) BlockAnzahl (Integer) Blöcke (BlockAnzahl * Blockgröße) | Das heisst, ich würde die Blöcke immer gleich gestalten, da ein Programm die Blöck eh immer nur in seiner aktuellen Form abspeichern kann. Wenn das Programm dann eine Datei mit alter Version laden muss, dann erkennt es die alte Version und konvertiert die alten Daten ins neue System. Wenn du Version der Datei jedoch höher ist, dann einfach das Laden abbrechen. Du kannst ja zum Beispiel die Ladefunktion in eine DLL auslagern um sie so einfach updaten zu können.
Also der einzige Unterschied zu deinem Beispiel ist, dass du jeweils nur einmal die Version am Anfang bestimmst und die folgenden Blöcke dann alle im selben Format sind. So sparst du dir auch diese CaseOf-Anweisungen.
Achja, zur Anzeige würde ich VirtualTreeView von [url= www.delphi-gems.com]Mike Lischke[/url] empfehlen. Die ist zum einen sehr schnell, individuell anpassbar, kostenlos und man kann die Daten ganz einfach verwalten.
Gruß Hape!
_________________ Manche antworten um ihren Beitragszähler zu erhöhen, andere um zu Helfen.
|
|
galagher
      
Beiträge: 2562
Erhaltene Danke: 46
Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
|
Verfasst: Fr 17.12.04 17:02
Es gibt eine Klasse TDataFile, das funktioniert wie INI-Dateien, nur binär und vor allem gibt es keine Beschränkung, wie lang die Datendatei werden darf! Leider gibt's den Link www.dbwork.chat.ru nicht mehr, ich habe aber die Datei DataFile.pas, als Autor steht da Momot Alexander (Deleon). Sie ist FreeWare. Wenn sowas erlaubt ist kann ich die Datei ja hier posten! (Weiss nicht, ob man fremden Code so einfach hier reinstellen darf)!
_________________ gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
|
|
Gausi 
      
Beiträge: 8554
Erhaltene Danke: 481
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Fr 17.12.04 18:41
Ich habe mal angefangen, meine Objekte um die Methoden SavetoStream und LoadfromStream zu erweitern. 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:
| procedure Tmp3File.LoadFromStream(str: Tstream); begin str.Read(groesse, SizeOf(groesse)); gelesen:=0; repeat str.Read(ID, sizeof(ID)); str.Read(len,sizeof(len)); case ID of 0: begin Setlength(Pfad, len); str.Read(Pchar(Pfad)^,len); end; 1: begin setlength(Artist, len); str.Read(Pchar(Artist)^,len); end; else begin str.Seek(len,soFromCurrent); end; end; inc(gelesen, sizeOf(ID) + SizeOf(Groesse) + len) until gelesen >= groesse; end;
procedure Tmp3File.SaveToStream(str: Tstream); begin groesse:=Berechnegroesse; str.Write(groesse,SizeOf(Groesse));
ID:=0; len:=length(Pfad); str.Write(ID,sizeof(ID)); str.Write(len,SizeOf(len)); str.Write(PChar(Pfad)^, len);
ID:=1; len:=length(Artist); str.Write(ID,sizeof(ID)); str.Write(len,SizeOf(len)); str.Write(PChar(Artist)^,len); end; |
Das funktioniert bisher in akzeptabler Geschwindigkeit. D.h. bei 30.000 Elementen weniger als 1 Sekunde. Das Gerüst steht also, und muss nur noch um die anderen Attribute erweitert werden...trotzdem bin ich weiterhin offen für weitere Anregungen und Optimierungsvorschläge
_________________ We are, we were and will not be.
|
|
|