Seite 1 von 2

Linked mit Struktur speichern (OOP)

Verfasst: 06.10.2009 19:45
von Freizeitcoder
Hallo zusammen,

ich versuche mich gerade dabei ein "Modul" für das Speichern von LinkedLists anzulegen. Leider scheitere ich dabei an folgendem Punkt.

Code: Alles auswählen

Procedure s_Strukturen_laden(File, Filename.s, Container, List Listname()) 
	If OpenFile(File,Filename)
		Anzahl_s.b = (Lof(0))/(SizeOf(Container)/4)			
		While Eof(0) = 0
			For i=0 To Anzahl_s
				AddElement(Listname())
				
				Listname\Name = ReadString(0)  ;;;;;;;;;; hier ist ende!
				Mahlzeit()\Zutaten = ReadString(0)
				Mahlzeit()\Zubereitung = ReadString(0)
				Mahlzeit()\Zeit = ReadByte(0)
				Mahlzeit()\Personen = ReadByte(0)
				Mahlzeit()\Bild = ReadString(0)
			Next
		Wend
	Else 
		MessageRequester("Error","Daten konnten nicht geladen werden!")
	EndIf
	CloseFile(0)
EndProcedure
Bitte erspart euch das geschriebene entziffern zu wollen. Ich scheitere einfach bei der Umstellung von normalem "Speichern" Aufruf zur Umstellung einer allgemeingültigen Funktion/Procedure/Modul. Obiger Code soll nur zeigen, daß ich mich damit auseinandergesetzt habe.

Nehmen wir einmal die folgende Struktur:

Code: Alles auswählen

Structure Mahlzeit_c
	Name.s
	Zutaten.s
	Zubereitung.s
	Zeit.s
	Personen.s
	Bild.s
EndStructure
Global NewList Mahlzeit.Mahlzeit_c()
Von dieser und ähnlicher Strukturen lege ich jeweils ein paar Elemente an. Im Hauptprogramm möchte ich nur noch den Funktionsaufruf "speichern" mit den notwendigen Parametern übergeben. Laden soll natürlich genauso laufen, und bekommt später auch solch eine Funktion. Die Menge der einzelnen Felder in einer Struktur ermittle ich über SizeOf(). Da alle meine Felder als Strings deklariert werden, kann ich mit SizeOf()/4 deren Anzahl ermitteln. Diesen Wert brauche ich nur noch mit LOF() und EOF() gegenrechnen, und erhalte somit alle Angaben die ich benötige um alles automatisch ablaufen zu lassen (Zeile für Zeile). Leider mache ich Fehler bei der Parameterübergabe an die Funktion und deren weitere Verwendung in der Funktion.

Ich hoffe es hat mich jemand verstanden, und kann mir vielleicht einen Tip geben.
Danke

Gruß

Edit: Die Containervariable wird jedesmal eine andere sein. Das heißt einmal will ich "Mahlzeit.Mahlzeiten_c()" speichern und einmal vielleicht soetwas "Wein.Weine_c()". Die Hilfe bringt mich also nicht weiter. Und wo wir gerade dabei sind.... die einzelnen Strukturfelder sind der Funktion natürlich genauso wenig bekannt wie deren Anzahl.
Na, ist das nicht mal eine schöner Knacker?! :) Wäre schön wenn jemand eine Lösung wüsste, oder mich auf einen anderen Weg schicken kann.
Danke euch.

Re: Linked mit Struktur speichern (OOP)

Verfasst: 06.10.2009 20:09
von Deluxe0321
Nur zum Verständnis, deine Gespeicherte Datei soll also ungefähr so aussehen?

Code: Alles auswählen

[Zeile] [Data]
1: Name des Essens
2: 200 g Zutat 1, 2 Messerspitzen Zutat 2, 3 Löffel Zutat 3
3: Zubereitung blabla bla
4: 45min
5: 5 Personen
6: Bildadresse.
7: Name des Essens 2... usw..
Wenn dem so ist, kannst du die werte so wie du sie beschrieben hast auslesen.
Wenn nicht wird die Sache schon etwas schwerer. Ich kann mir nicht vorstellen,
dass du die Zubereitung in einem Satz, bzw. in einer Zeile ohne Umbruch speicherst.
Die Strings der verschieden Daten geraten in deinem Verfahren sonst ziemlich durcheinander.

Die Verwendung von LOF() ist meiner Meinung nach auch fehl am Platz. LOF() gibt die Größe in Bytes aus, nicht die "Länge" der Datei.

Code: Alles auswählen

Text1
Text2
Text3
Text4
gibt von der dir berechneten "Zeilenanzahl" etwas anderes aus als:

Code: Alles auswählen

TEXT1 TEXT1 TEXT1 TEXT1
TEXT2 TEXT2 TEXT2
TEXT3 TEXT3
TEXT4 TEXT4
mit deiner Stucture oben ist die Ausgabe Codeblock1: 4 Zeilen & Codeblock2: 11 Zeilen . ;)

Möglicher Ansatz:
Speichere die Daten ungefähr so:

Code: Alles auswählen

(Int) Länge/größe des Strings
(String) Text in besagter Länge
(Int) Länge/Größe des nächsten Strings
(String) Text in besagter Länge
Damit verwurschtelst du dich nicht.

Grüße Marv
//Edit: Schnell schreiben bringt einem zum übertippen von Buchstaben ^^

Re: Linked mit Struktur speichern (OOP)

Verfasst: 06.10.2009 20:33
von Freizeitcoder
Danke für den Hinweis. Darauf werde ich achten.

Wenn jedoch nicht noch eine Meldung kommt ob es überhaupt möglich ist ein Modul für das Speichern von LinkedLists zu erstellen, werde ich mir eine komplett andere Lösung suchen müssen. ;(
Ich befürchte ich müßte ein eigenständiges Programm schreiben um die dynamischen Strukturen zu speichern. Gibt es vielleicht noch andere Ansätze?

Ich möchte nur ungern auf die Strukturen verzichten. Mit ihnen lässt sich alles andere schön sauber und einläuchtend programmieren. ;(
Gruß

Re: Linked mit Struktur speichern (OOP)

Verfasst: 06.10.2009 21:13
von Kaeru Gaman
ich versteh deinen Aufruf nicht so ganz...
wieso Container als Parameter, und wieso SizeOf...
wenn du den ohne Typ angibst, ist der immer Integer, also wird dieses SizeOf sowieso immer 4 sein (wenn als win32 compiliert)
und wieso schreibst du überall als FileNummer eine 0, wenn du im Open die Nummer File verwendest?
und du musst natürlich eine Liste erzeugen bevor du neue Elemente lädst, das muss also außerhalb stattfinden.


weiterhin:
natürlich kannst du per Funktion eine Liste speichern.
Da Listen nicht fortlaufend im Speicher stehen sondern Elementweise, und außerdem Strings nicht in den Elementen selber,
musst du jedes Element einzeln schreiben/lesen.

Wenn du ein strukturiertes Array verwendest und dort drin FixedStrings, kannst du das gesamte Array auf einen Rutsch laden/speichern..

Re: Linked mit Struktur speichern (OOP)

Verfasst: 06.10.2009 22:17
von STARGÅTE
Ich konnte dem Thema nicht ganz folgen aber ist dein Ziel sowas:

Code: Alles auswählen

Structure TestStruktur
 Long.l
 String.s
 Byte.b
EndStructure

NewList Test.Test()

For n = 1 To 5
 Test()\Long = 10000
 Test()\String = "Laber Laber"
 Test()\Byte = 20
Next

CreateFile(0, "Temp.txt")
 WriteLinkedList(0, Test(), TestStruktur)
CloseFile(0)
Du erstellst eine Liste mit einer Struktur und Inhalt und kannst diese dann mit einem einzigen befehl komplett speichern?

UNd dnan halt später auch wieder Einladen ...

Wenn ja kann ich dir sowas schreiben.

Proceduren für das Speichern von Strukturen und ganzen Arrays mit Strukturen (egal wie verschachtelt und ob mit Strings) habe ich schon, LinkedList wäre ja nur ein weiterer schritt

Re: Linked mit Struktur speichern (OOP)

Verfasst: 07.10.2009 00:13
von Deluxe0321
Nein, sowie ich das verstanden habe hat er eine String-only Struktur, bzw. Linkedlist (siehe Startposting).
Er will nun die Liste komplett speichern & wieder einlesen können.

Kaerus Vorschlag mit FixedStrings zu arbeiten wäre auch eine Option, dann könnte er aber gleich eine DB verwenden; der Aufwand wäre damit um einiges geringer (? zudem würde unnötig Speicherplatz verschwendet werden ?). Zubereitungsbeschreibungen habe nicht immer die gleiche Länge und können sich manchmal auch einem Roman annähern ;)

@Freizeitcoder
Such mal hier im Board nach Linkedlist speichern oder änlichem. Vll. hilft dir ja auch dieser Post: http://purebasic.fr/german/viewtopic.php?p=42587#p42587

Grüße Marv

Re: Linked mit Struktur speichern (OOP)

Verfasst: 07.10.2009 00:38
von Kiffi
ich würde für solche Zwecke die Preferences-Befehle verwenden.

Damit vergeudet man zum einen nicht viel Speicherplatz und zum
anderen kann die Struktur jederzeit um Elemente erweitert oder
verringert werden, ohne dass es Probleme beim Auslesen der
Datei gibt.

Code: Alles auswählen

EnableExplicit

Structure Mahlzeit_c
  Name.s
  Zutaten.s
  Zubereitung.s
  Zeit.s
  Personen.s
  Bild.s
EndStructure

Global NewList Mahlzeit.Mahlzeit_c()

Procedure MahlzeitenLaden()
  
  Protected DatensatzZaehler
  Protected Name.s
  
  ClearList(Mahlzeit())
  
  If OpenPreferences("Mahlzeiten.dat")
    
    Repeat
      
      Name = ReadPreferenceString("Name" + Str(DatensatzZaehler), "")
      
      If Name = ""
        Break
      EndIf
      
      AddElement(Mahlzeit())
      
      Mahlzeit()\Name        = Name
      Mahlzeit()\Zutaten     = ReadPreferenceString("Zutaten" + Str(DatensatzZaehler), "")
      Mahlzeit()\Zubereitung = ReadPreferenceString("Zubereitung" + Str(DatensatzZaehler), "")
      Mahlzeit()\Zeit        = ReadPreferenceString("Zeit" + Str(DatensatzZaehler), "")
      Mahlzeit()\Personen    = ReadPreferenceString("Personen" + Str(DatensatzZaehler), "")
      Mahlzeit()\Bild        = ReadPreferenceString("Bild" + Str(DatensatzZaehler), "")
      
      DatensatzZaehler + 1
      
    ForEver
    
    ClosePreferences()
    
  EndIf
  
EndProcedure

Procedure MahlzeitenSpeichern()
  
  If CreatePreferences("Mahlzeiten.dat")
    
    ForEach Mahlzeit()
      
      WritePreferenceString("Name" + Str(ListIndex(Mahlzeit())),        Mahlzeit()\Name)
      WritePreferenceString("Zutaten" + Str(ListIndex(Mahlzeit())),     Mahlzeit()\Zutaten)
      WritePreferenceString("Zubereitung" + Str(ListIndex(Mahlzeit())), Mahlzeit()\Zubereitung)
      WritePreferenceString("Zeit" + Str(ListIndex(Mahlzeit())),        Mahlzeit()\Zeit)
      WritePreferenceString("Personen" + Str(ListIndex(Mahlzeit())),    Mahlzeit()\Personen)
      WritePreferenceString("Bild" + Str(ListIndex(Mahlzeit())),        Mahlzeit()\Bild)
      
    Next
    
    ClosePreferences()
    
  EndIf
  
EndProcedure
(nicht berücksichtigt im obigen Code sind Zeilenumbrüche in den jeweiligen
Werten. Die müssten dann gegebenenfalls escaped werden)

Grüße ... Kiffi

Re: Linked mit Struktur speichern (OOP)

Verfasst: 07.10.2009 00:49
von Deluxe0321
Sorry für die Frage aber sind die Preference-Files nicht von der Größe her begrenzt?
Windows setzt doch eine Grenze von 64kb falls ich mich recht entsinne, oder nutzt PB nicht die API?

Bsp für das was ich oben beschrieb (schnell runter gehackt, geht sicherlich noch besser):

Code: Alles auswählen

Structure StringTest
  String1.s
  String2.s
  String3.s
EndStructure

NewList StringTest.StringTest()

Procedure SaveList(List StringTest.StringTest(),File.s)
  Protected Size1.i,Size2.i,Size3.i
  
  If ListSize(StringTest()) And File.s
    
    If CreateFile(0,File.s)
      
      ;Zuerst schreiben wir die Anzahl der Einträge - sozusagen ein billiger Header.
      WriteInteger(0,ListSize(StringTest()))
      ;Hier kannst du noch weitere Informationen einfügen z.B. Datum, copyright usw.
      
      ForEach StringTest() : With StringTest()
          
        ;Zuerst wird die Länge des Strings in byte ermittelt.
        Size1.i = StringByteLength(\String1.s)
        Size2.i = StringByteLength(\String2.s)
        Size3.i = StringByteLength(\String3.s)
        
        ;Jetzt schreiben wir die Länge des Strings & den String selbst in die Datei
        WriteInteger(0,Size1.i)
        WriteData(0,@StringTest()\String1.s,Size1.i)
      
        WriteInteger(0,Size2.i)
        WriteData(0,@StringTest()\String2.s,Size2.i)
        
        WriteInteger(0,Size3.i)
        WriteData(0,@StringTest()\String3.s,Size3.i)              
      
        
      EndWith : Next
      
      CloseFile(0)
      
    EndIf
    
    
  EndIf
EndProcedure

Procedure LoadList(List StringTest.StringTest(),File.s)
  Protected Size1.i,Size2.i,Size3.i,Eintraege.i,a.i,*mem
  
  If FileSize(File.s) > -1
    
    If ReadFile(0,File.s)
      
      ; Anzahl der Einträge auslesen..
      Eintraege.i = ReadInteger(0)
      
      If Eintraege.i
        
        For a=1 To Eintraege.i
          
          ;Einlesen der Daten nach gespeicherter Länge..
          AddElement(StringTest())
          
          Size1.i = ReadInteger(0)  : *mem = AllocateMemory(Size1.i)
          ReadData(0,*mem,Size1.i)  : StringTest()\String1.s = PeekS(*mem,Size1.i)
          
          Size2.i = ReadInteger(0)  : ReAllocateMemory(*mem,Size2.i)
          ReadData(0,*mem,Size2.i)  : StringTest()\String2.s = PeekS(*mem,Size2.i)          
          
          Size3.i = ReadInteger(0)  : ReAllocateMemory(*mem,Size3.i)
          ReadData(0,*mem,Size3.i)  : StringTest()\String3.s = PeekS(*mem,Size3.i)           
          
          FreeMemory(*mem)
          
        Next
        
      EndIf
      
      CloseFile(0)
      
    EndIf
    
    
  EndIf
EndProcedure

; ----------------------------------------------
; Teil zum testen der Prozeduren...

Define a.i,b.i,c.i,WString.s,Test.i

For a=0 To 5
  AddElement(StringTest())
  
  For b=0 To 2
    For c=1 To Random(300)
      WString.s + Chr(Random(25) + 65)
      
      If Random(30) = 1
        WString.s + #CRLF$ ;ab und zu mal ein Zeilenumbruch in den String setzten
      EndIf      
      
    Next
    
    Select b
      Case 0
        StringTest()\String1.s = WString.s  
      Case 1
        StringTest()\String2.s = WString.s  
      Case 2
        StringTest()\String3.s = WString.s  
    EndSelect
    WString.s = ""
    
  Next
Next

Debug "Liste Speichern..."
SaveList(StringTest(),"C:\Test.txt")

ForEach StringTest()
  Debug StringTest()\String1.s
  Debug StringTest()\String2.s  
  Debug StringTest()\String3.s  
Next

Debug "" : Debug ""
ClearList(StringTest())  

Debug "List Laden.."
LoadList(StringTest(),"C:\Test.txt")

ForEach StringTest()
  Debug StringTest()\String1.s
  Debug StringTest()\String2.s  
  Debug StringTest()\String3.s  
Next
Grüße und Danke
Marv

Re: Linked mit Struktur speichern (OOP)

Verfasst: 07.10.2009 12:38
von Freizeitcoder
Hallo zusammen,

danke für die vielen Antworten. Ich kann leider den Leuten die dieses Thema nach mir suchen noch keine endgültige Lösung vorschlagen. Am meisten Kopfzerbrechen macht mir das Feld "Zubereitung". Wie schon erwähnt worden ist, kann dieses Feld von "sehr kurz" bis "Herr der Ringe war ein Dreck dagegen" reichen. Ich werde die nächste Zeit damit verbringen die ganzen Vorschläge aufzuarbeiten, und mir ein besseres Bild der zu erwartenden Probleme zu verschaffen.

Über die Preferences bin ich auch schon gestolpert. Durch ihre einfache Handhabung, und die mögliche Gruppierungen haben sie mir gleich gefallen. Für meine zukünftigen Projekte wäre es schon interessant, ob ihre Größe wirklich beschränkt ist. In der Hilfe habe ich dazu keine Bemerkung gefunden. (Auch einer der Punkte die ich noch ausprobieren muß.)

Gruß an alle

Re: Linked mit Struktur speichern (OOP)

Verfasst: 07.10.2009 12:54
von ts-soft
Deluxe0321 hat geschrieben:Sorry für die Frage aber sind die Preference-Files nicht von der Größe her begrenzt?
Windows setzt doch eine Grenze von 64kb falls ich mich recht entsinne, oder nutzt PB nicht die API?
PB nutzt hier nicht die WinAPI, PreferenceFiles sind in der Größe nicht beschränkt, bzw. ab einer gewissen
Größe machen Preferences wohl keinen Sinn mehr :mrgreen: