Put# und Get# in Pure Basic

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag von ts-soft »

Einsatzzwecke gibts aber auch heute noch und man kann beim entwickeln
solcher Algorithm auch einige Grundlagen bezüglich File und Memory ver-
stehen lernen :wink:

Z.B. Leveldaten könnten eine fixe Größe haben und nacheinander benötigt
werden, eine Datenbank hätte hier zuviel unnötigen Overhead.

Ansonsten stimme ich euch natürlich zu.
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
mikstart
Beiträge: 25
Registriert: 23.07.2009 23:12

Beitrag von mikstart »

Code: Alles auswählen

Structure RecSet
  Name.s[20]
  Price.q
  Units.l
EndStructure

Dim DataBase.RecSet(800)


; Datensatz Suchen
FileSeek( #DB, RecordNumber * SizeOf( RecSet ) )

; Datensatz schreiben
WriteString( #DB, DataBase(RecordNumber)\Name  )
WriteQuad  ( #DB, DataBase(RecordNumber)\Price )
WriteLong  ( #DB, DataBase(RecordNumber)\Units )

; Datensatz lesen
DataBase(RecordNumber)\Name  = ReadString( #DB )
DataBase(RecordNumber)\Price = ReadQuad  ( #DB )
DataBase(RecordNumber)\Units = ReadLong  ( #DB )

; komplette Tabelle schreiben
WriteData( #DB, @DataBase(), NumberOfRecords * SizeOf( RecSet ) )

; komplette Tabelle lesen
ReadData( #DB, @DataBase(), NumberOfRecords * SizeOf( RecSet ) )
sieht nicht schlecht aus.

ich muss doch noch CreateFile(#DB, DataBase.RecSet(800)). geht aber nicht. der hat immer was an db auszusetzen, ob ich mit create oder ohne. was hat das mit #DB auf sich? db wird ja wohl für datenbank stehen, aber wie muss ich definieren das dieses beispiel läuft.


@Kiffi und Kaeru Gaman

lasst mich erst mal laufen lernen und die ganzen grund begriffe von pure basic verstehen, in ein paar monaten können wir mal über sql reden.

gruss mik
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

@ts
im Prinzip ja, aber...

die Anforderung, gleich groß portionierte Leveldaten sequenziell zu laden,
halte ich für einen extremen Sonderfall.

normalerweise würde man Levelweise vorgehen, da lädt man einen ganzen Level auf einen Rutsch,
was bei heutigen Hauptspeichergrößen kein Problem darstellt.
Außerdem können hierbei Level unterschiedlich groß sein und unterschiedlich viel Inhalt haben.

wenn man die Level nicht in getrennten Files haben will, steht man wieder vor der Datenbank-Frage,
weil nicht nur Level unterschiedlich groß sein können,
sondern auch gleiche Objekte in unterschiedlichen Leveln bzw. Sektoren vorkommen können.

Natürlich ist es grundsätzlich gut zu wissen wie ein RandomAccessFile funktioniert,
aber die tatsächlichen Anwendungen sind heutzutage so gut wie ausgestorben.

im vorliegenden Fall soll es wohl um eine Stammdaten-Verwaltung gehen, das ist das klassische Schulbeispiel für SQL-Benutzung.
Zuletzt geändert von Kaeru Gaman am 29.07.2009 14:19, insgesamt 1-mal geändert.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

mikstart hat geschrieben:ich muss doch noch CreateFile(#DB, DataBase.RecSet(800)). geht aber nicht. der hat immer was an db auszusetzen, ob ich mit create oder ohne. was hat das mit #DB auf sich? db wird ja wohl für datenbank stehen, aber wie muss ich definieren das dieses beispiel läuft.
das ist nur ein snippet das das Prinzip zeigen soll.

#DB ist eine Konstante, deine momentane FileNummer, setz die am Anfang einfach auf Null.

Code: Alles auswählen

#DB = 0
und als Name bei CreateFile musst du latürnich einen Datei-Namen angeben

Code: Alles auswählen

CreateFile(#DB, DataBase.RecSet(800))
ist ja absolut abenteuerlich!

bitte doch auch ein wenig die Help lesen und nicht Buchstaben ins Blaue werfen.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
mikstart
Beiträge: 25
Registriert: 23.07.2009 23:12

Beitrag von mikstart »

du wirst lachen, ich hab die hilfe ständig offen nur manchmal versteh ich nur bahnhof. hatte nur auf die anwendungsmöglichkeiten von create geschaut und kam dann auf das abenteuerliche. dabei steht ganz oben sogar fett "Ergebnis = OpenFile(#Datei, DateiName$)"

nun hab ich folgendes:

Code: Alles auswählen

Structure RecSet 
  
  Name.s[20] 
  Price.q 
  Units.l 
EndStructure 

Dim DataBase.RecSet(900)

#DB = 1
datei$ = "dat"

CreateFile(#DB, datei$)
CloseFile(#DB)


OpenFile(#DB, Datei$)

For RecordNumber = 100 To 900
units.l = units.l +1

; Datensatz schreiben 
WriteString( #DB, DataBase(RecordNumber)\Name  ) 
WriteQuad  ( #DB, DataBase(RecordNumber)\Price ) 
WriteLong  ( #DB, DataBase(RecordNumber)\Units ) 
Next RecordNumber

CloseFile(#DB)
die recordnumber ist doch die datensatz nummer oder?
dann müsste er doch praktisch in der dat von 100 bis 900 stehen.
spätestens bei units.l müsste in der dat 1 bis 800 stehen haben.
aber ich sehe nichts wenn ich dat mit den text editor aufmache.
die datei dat hat aber 9,38 kb.

und wie kan ich das auf den bildschirm bringen wenn ich mit ReadString ausgelesen habe, mit print geht das irgendwie nicht.

gruss mik
Zuletzt geändert von mikstart am 29.07.2009 19:40, insgesamt 1-mal geändert.
Benutzeravatar
ZeHa
Beiträge: 4760
Registriert: 15.09.2004 23:57
Wohnort: Friedrichshafen
Kontaktdaten:

Beitrag von ZeHa »

ts-soft spricht über das Speichern von Leveldaten... daß ich das noch erleben darf :bounce:
Bild     Bild

ZeHa hat bisher kein Danke erhalten.
Klicke hier, wenn Du wissen möchtest, woran ihm das vorbeigeht.
Benutzeravatar
H.Brill
Beiträge: 496
Registriert: 15.10.2004 17:42
Wohnort: 66557 Neunkirchen

Beitrag von H.Brill »

Hallo,
Datensatznummer gibt es so nicht.
Du kannst dir aber mit ein wenig Aufwand
das ganze als Proceduren schreiben.
Dazu brauchst du die Länge der Structure
und die PB Funktionen Lof() und Fileseek().
Also :
1. Datensatz auf Position 0
2. Datensatz auf SizeOf(deineStructure)
usw.

Damit kann man leicht errechnen, wo Datensatz x
liegt, bzw. wo man mit Fileseek() hinspringen muß,
um ihn zu überschreiben.

PS : Wenn es nicht zuviele Datensätze sind, kann man
auch die Preference benutzen. Einfach die Gruppen
(Ergebnis = PreferenceGroup(Name$)) durchnummerieren,
also [1], [2] usw und dazwischen deine Daten.
z.B:
[1]
Artikel = "Festplatte"
Stueck = 10
Preis = 50.00
[2]
.....
Geht dann sehr einfach mit WritePreferenceString,
WritePrefernceInteger und WritePrefenceFloat bzw.
ReadPreference....

Alles weitere schaue in der Hilfe.
PB 6.10
Benutzeravatar
mk-soft
Beiträge: 3845
Registriert: 24.11.2004 13:12
Wohnort: Germany

Beitrag von mk-soft »

Habe mal Put und Get nachgebaut... Ist aber erst mal ein anfang.

Code: Alles auswählen



; *****************************************************************************

#FileDB = 0
Global FileMax

Procedure OpenDB(name.s, size)

  If OpenFile(#FileDB, name)
    FileMax = Lof(#FileDB)
    FileMax / size
    FileMax - 1
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
  
EndProcedure


Procedure CloseDB()

  If IsFile(#FileDB)
    CloseFile(#FileDB)
  EndIf
EndProcedure

Procedure GetDB(id, *pdata, size)
  
  Protected pos, len
  
  If id > FileMax
    ProcedureReturn #False
  EndIf
  
  pos = id * size
  FileSeek(#FileDB, pos)
  len = ReadData(#FileDB, *pdata, size)
 
  If len = size
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
  
EndProcedure

Procedure PutDB(id, *pdata, size)

  Protected pos, len
  
  If id > FileMax + 1
    ProcedureReturn #False
  EndIf
  
  pos = id * size
  FileSeek(#FileDB, pos)
  len = WriteData(#FileDB, *pdata, size)
  If len = size
    FileMax + 1
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
  
EndProcedure

; *****************************************************************************

Structure udtData
  Name.s{20}
  Price.d
  Units.l
EndStructure

Global dataOut.udtData, dataIn.udtData

Debug "Open DB"
If OpenDB("TestDB.DAT", SizeOf(udtData))
  Debug "Ok."
Else
  Debug "Error Open"
  End
EndIf

Debug "Put..."

For id = 0 To 10
  With dataOut
    \Name = "Name ID " + Str(id)
    \Price = 10.5 + id
    \Units = 100 + id
  EndWith
  If PutDB(id, dataOut, SizeOf(udtData))
    Debug "PutDB Ok."
  Else
    Debug "PutDB Error"
  EndIf
Next

Debug "Change..."
  id = 5
  With dataOut
    \Name = "Hallo Welt: " + Str(id)
    \Price = 99.8
    \Units = 1000 
  EndWith
  If PutDB(id, dataOut, SizeOf(udtData))
    Debug "PutDB Ok."
  Else
    Debug "PutDB Error"
  EndIf

Debug "Get..."
For id = 0 To 11
  If GetDB(id, dataIn, SizeOf(udtData))
    With dataIn
      Debug "ID     : " + Str(id)
      Debug "Name   : " + \Name
      Debug "Price  : " + StrD(\Price)
      Debug "Units  : " + Str(\Units)
    EndWith
  Else
    Debug "GetDB Error"
  EndIf
Next

CloseDB()

FF :wink:
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
mikstart
Beiträge: 25
Registriert: 23.07.2009 23:12

Beitrag von mikstart »

mk-soft hat geschrieben:Habe mal Put und Get nachgebaut... Ist aber erst mal ein anfang.

Code: Alles auswählen

[/quote]


wow, hab gar nicht gewusst das man so viel code dafür braucht.

1000 dank

gruss mik
Benutzeravatar
mk-soft
Beiträge: 3845
Registriert: 24.11.2004 13:12
Wohnort: Germany

Beitrag von mk-soft »

Das ist doch nicht viel Code :roll:

Lof(...) funktioniert doch richtig. Habe mal den Code überarbeitet

Code: Alles auswählen

; *****************************************************************************

#FileDB = 0

Procedure OpenDB(name.s)

  If OpenFile(#FileDB, name)
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
 
EndProcedure


Procedure CloseDB()

  If IsFile(#FileDB)
    CloseFile(#FileDB)
  EndIf
EndProcedure

Procedure GetDB(id, *pdata, size)
 
  Protected max, pos, len
  
  If IsFile(#FileDB) = #False
    ProcedureReturn #False
  EndIf
  
  max = Lof(#FileDB)
  max / size
  max - 1
  
  If id > max
    ProcedureReturn #False
  EndIf
 
  pos = id * size
  FileSeek(#FileDB, pos)
  len = ReadData(#FileDB, *pdata, size)
 
  If len = size
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
 
EndProcedure

Procedure PutDB(id, *pdata, size)

  Protected max, pos, len
  
  If IsFile(#FileDB) = #False
    ProcedureReturn #False
  EndIf
  
  max = Lof(#FileDB)
  max / size
  
  If id > max
    ProcedureReturn #False
  EndIf
 
  pos = id * size
  FileSeek(#FileDB, pos)
  len = WriteData(#FileDB, *pdata, size)
  If len = size
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
 
EndProcedure

; *****************************************************************************

Structure udtData
  Name.s{20}
  Price.d
  Units.l
EndStructure

Global dataOut.udtData, dataIn.udtData

Debug "Open DB"
If OpenDB("TestDB.DAT")
  Debug "Ok."
Else
  Debug "Error Open"
  End
EndIf

Debug Lof(#FileDB)

Debug "Put..."

For id = 0 To 10
  With dataOut
    \Name = "Name ID " + Str(id)
    \Price = 10.5 + id
    \Units = 100 + id
  EndWith
  If PutDB(id, dataOut, SizeOf(udtData))
    Debug "PutDB Ok."
  Else
    Debug "PutDB Error"
  EndIf
Next

Debug "Change..."
  id = 5
  With dataOut
    \Name = "Hallo Welt: " + Str(id)
    \Price = 99.8
    \Units = 1000
  EndWith
  If PutDB(id, dataOut, SizeOf(udtData))
    Debug "PutDB Ok."
  Else
    Debug "PutDB Error"
  EndIf

Debug "Get..."
For id = 0 To 11
  If GetDB(id, dataIn, SizeOf(udtData))
    With dataIn
      Debug "ID     : " + Str(id)
      Debug "Name   : " + \Name
      Debug "Price  : " + StrD(\Price)
      Debug "Units  : " + Str(\Units)
    EndWith
  Else
    Debug "GetDB Error"
  EndIf
Next

CloseDB()
FF :wink:
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Antworten