Details:
- Blöcke können nur am Ende eingefügt werden
- Blöcke können nicht mehr gelöscht werden
- Alles besteht nur aus einem Speicherblock
Der Vorteil gegenüber LinkedList besteht darin das ich alles in einem Speicherblock habe und nicht lauter kleine, verkettete Speicherblöcke, wodurch das ganze einfach als Datei usw. gespeichert werden kann. Außerdem ist der Overhead kleiner.
Kleine Beispiel: Du liest eine eine große Datei ein, baust dir daraus mit dem Builder einen Stream, schickst die einzelnen Blöcke über Netzwerk weiter, die Gegenstelle setzt das Ganze mit dem Builder wieder zu einem Stream zusammen und der Loader macht draus wieder eine Datei, ganz einfach

Democode am Ende:
Code: Alles auswählen
; ------------------------------------------------------------------------------------
; Memory - Streaming
; Bauen und lesen von MemoryBlöcken in Streamformat mit Variabler Blockgröße
; Overhead pro Block: 2*SizeOf(INTEGER) (x86: 8 Byte, x64: 16 Byte)
; (c) Alexander Aigner
; PB 4.3+ x86/x64 Ascii/Unicode
; ------------------------------------------------------------------------------------
; ------------------------------------------------------------------------------------
; Structures & Prototypes
; ------------------------------------------------------------------------------------
Structure MemoryStream
*Cur
*Start
Size.i
EndStructure
Prototype MS_StartStream(UserData.i)
Prototype MS_StopStream(UserData.i)
Prototype MS_StreamCB(*Mem, MemSize, StreamedSize, UserData.i)
; ------------------------------------------------------------------------------------
; Builder
; ------------------------------------------------------------------------------------
; Builder initialisieren
Procedure MS_Builder_Init()
Protected *Stream.MemoryStream = AllocateMemory(SizeOf(MemoryStream))
ProcedureReturn *Stream
EndProcedure
; Builder deinitialisieren
Procedure MS_Builder_DeInit(*Stream.MemoryStream)
FreeMemory(*Stream)
EndProcedure
; Speicherblock zum Stream hinzufügen
Procedure MS_Builder_AddBlock(*Stream.MemoryStream, *Mem, MemSize)
Protected LastSize
With *Stream
If Not \Start
; Start - Block erzeugen
\Start = AllocateMemory(MemSize + 2*SizeOf(INTEGER))
\Cur = \Start
\Size = MemSize + 2*SizeOf(INTEGER)
; Positionen Schreiben
PokeI(\Cur, 0)
PokeI(\Cur + SizeOf(INTEGER), MemSize)
Else
LastSize = PeekI(\Cur + SizeOf(INTEGER))
; Block anhängen
\Start = ReAllocateMemory(\Start, \Size + MemSize + 2*SizeOf(INTEGER))
\Cur = \Start + \Size
\Size + MemSize + 2*SizeOf(INTEGER)
; Positionen Schreiben
PokeI(\Cur, LastSize)
PokeI(\Cur + SizeOf(INTEGER), MemSize)
EndIf
CopyMemory(*Mem, \Cur + 2*SizeOf(INTEGER), MemSize)
EndWith
EndProcedure
; Stream abschließen
Procedure MS_Builder_Finish(*Stream.MemoryStream)
Protected LastSize
With *Stream
If Not \Start
\Start = AllocateMemory(4*SizeOf(INTEGER))
\Cur = \Start
\Size = 4
Else
LastSize = PeekI(\Cur + SizeOf(INTEGER))
\Start = ReAllocateMemory(\Start, \Size + 2*SizeOf(INTEGER))
\Cur = \Start + \Size
\Size + 2*SizeOf(INTEGER)
; Positionen Schreiben
PokeI(\Cur, LastSize)
PokeI(\Cur + SizeOf(INTEGER), 0)
EndIf
EndWith
EndProcedure
; Splittet einen Speicherblock auf
Procedure MS_Builder_Splitt(*Stream.MemoryStream, *Mem, MemSize, BlockSize)
Protected Count
Count = Round(MemSize/BlockSize, 0)
For i = 0 To Count
If (i + 1)*BlockSize>MemSize
MS_Builder_AddBlock(*Stream, *Mem + (i*BlockSize), BlockSize-((i + 1)*BlockSize-MemSize))
Else
MS_Builder_AddBlock(*Stream, *Mem + (i*BlockSize), BlockSize)
EndIf
Next
EndProcedure
; Stream Speicheraddresse
Procedure MS_Builder_GetMem(*Stream.MemoryStream)
With *Stream
ProcedureReturn \Start
EndWith
EndProcedure
; Stream Speichergröße
Procedure MS_Builder_GetMemSize(*Stream.MemoryStream)
With *Stream
ProcedureReturn \Size
EndWith
EndProcedure
; Konvertiert Datei zu Stream
Procedure MS_Builder_FileToStream(*Stream.MemoryStream, FileName.s, BlockSize)
Protected *Mem, FileSize, File = ReadFile(#PB_Any, FileName)
If File
FileSize = Lof(File)
*Mem = AllocateMemory(FileSize)
ReadData(File, *Mem, FileSize)
CloseFile(File)
MS_Builder_Splitt(*Stream, *Mem, FileSize, BlockSize)
EndIf
EndProcedure
; Speichert den Stream in einer Datei
Procedure MS_Builder_SaveToFile(*Stream.MemoryStream, FileName.s)
Protected File = CreateFile(#PB_Any, FileName)
If File
WriteData(File, MS_Builder_GetMem(*Stream), MS_Builder_GetMemSize(*Stream))
CloseFile(File)
EndIf
EndProcedure
; ------------------------------------------------------------------------------------
; Loader
; ------------------------------------------------------------------------------------
; Loader initialisieren
Procedure MS_Loader_Init(*StreamMemory, MemSize)
Protected *Stream.MemoryStream = AllocateMemory(SizeOf(MemoryStream))
With *Stream
\Start = *StreamMemory
\Cur = *StreamMemory
\Size = MemSize
ProcedureReturn *Stream
EndWith
EndProcedure
; Loader aus Datei initialisieren
Procedure MS_Loader_InitFromFile(FileName.s)
Protected *Mem, File = ReadFile(#PB_Any, FileName)
If File
FileSize = Lof(File)
*Mem = AllocateMemory(FileSize)
ReadData(File, *Mem, FileSize)
CloseFile(File)
ProcedureReturn MS_Loader_Init(*Mem, FileSize)
EndIf
EndProcedure
; Loader deinitialisieren
Procedure MS_Loader_DeInit(*Stream.MemoryStream)
With *Stream
FreeMemory(\Start)
FreeMemory(*Stream)
EndWith
EndProcedure
; Aktuelle Speicherblockaddresse
Procedure MS_Loader_GetMem(*Stream.MemoryStream)
With *Stream
ProcedureReturn \Cur + 2*SizeOf(INTEGER)
EndWith
EndProcedure
; Aktuelle Speicherblockgröße
Procedure MS_Loader_GetMemSize(*Stream.MemoryStream)
With *Stream
ProcedureReturn PeekI(\Cur + SizeOf(INTEGER))
EndWith
EndProcedure
; zum nächsten Speicherblock
Procedure MS_Loader_NextBlock(*Stream.MemoryStream)
Protected RtVar
With *Stream
\Cur + PeekI(\Cur + SizeOf(INTEGER)) + 2*SizeOf(INTEGER)
If (\Cur-\Start)> = (\Size-2*SizeOf(INTEGER))
RtVar = #False
Else
RtVar = #True
EndIf
ProcedureReturn RtVar
EndWith
EndProcedure
; zum vorherigen Speicherblock
Procedure MS_Loader_PreviousBlock(*Stream.MemoryStream)
Protected RtVar, LastSize
With *Stream
LastSize = PeekI(\Cur)
If Not LastSize
RtVar = #False
Else
\Cur-(LastSize + 2*SizeOf(INTEGER))
RtVar = #True
EndIf
ProcedureReturn RtVar
EndWith
EndProcedure
; zum ersten Speicherblock
Procedure MS_Loader_FirstBlock(*Stream.MemoryStream)
With *Stream
\Cur = \Start
EndWith
EndProcedure
; aktuelle BlockID holen
Procedure MS_Loader_GetBlock(*Stream.MemoryStream)
With *Stream
ProcedureReturn \Cur
EndWith
EndProcedure
; aktuellen Block setzen
Procedure MS_Loader_SetBlock(*Stream.MemoryStream, *Block)
With *Stream
\Cur = *Block
EndWith
EndProcedure
; Stream wieder zusammensetzen
Procedure MS_Loader_Merge(*Stream.MemoryStream)
Protected BlockSize = 0, Size = 0
Protected *Mem = AllocateMemory(1)
Protected Block = MS_Loader_GetBlock(*Stream)
MS_Loader_FirstBlock(*Stream)
Repeat
BlockSize = MS_Loader_GetMemSize(*Stream)
*Mem = ReAllocateMemory(*Mem, Size + BlockSize)
CopyMemory(MS_Loader_GetMem(*Stream), *Mem + Size, BlockSize)
Size + BlockSize
Until Not MS_Loader_NextBlock(*Stream)
MS_Loader_SetBlock(*Stream, Block)
ProcedureReturn *Mem
EndProcedure
; Streamt den Speicher an ein Callback
Procedure MS_Loader_Stream(*Stream.MemoryStream, *StartStream.MS_StartStream, *StopStream.MS_StopStream, *StreamCB.MS_StreamCB, UserData.i)
Protected CurrentSize, StreamedSize, Block = MS_Loader_GetBlock(*Stream)
With *Stream
*StartStream(UserData)
MS_Loader_FirstBlock(*Stream)
Repeat
CurrentSize = MS_Loader_GetMemSize(*Stream)
StreamedSize + CurrentSize
*StreamCB(MS_Loader_GetMem(*Stream), CurrentSize, StreamedSize, UserData)
Until Not MS_Loader_NextBlock(*Stream)
MS_Loader_SetBlock(*Stream, Block)
*StopStream(UserData)
EndWith
EndProcedure
; Konvertiert eine Datei direkt in eine StreamDatei
Procedure MS_Misc_FileToStream(FileName.s, StreamFileName.s, BlockSize)
Protected *Mem, Builder = MS_Builder_Init()
MS_Builder_FileToStream(Builder, FileName, BlockSize)
MS_Builder_Finish(Builder)
MS_Builder_SaveToFile(Builder, StreamFileName)
*Mem = MS_Builder_GetMem(Builder)
MS_Builder_DeInit(Builder)
FreeMemory(*Mem)
EndProcedure
; Konvertiert eine StreamDatei direkt in eine Datei
Procedure MS_Misc_StreamToFile(StreamFileName.s, FileName.s)
Protected File, *Mem, Loader = MS_Loader_InitFromFile(StreamFileName)
*Mem = MS_Loader_Merge(Loader)
MS_Loader_DeInit(Loader)
File = CreateFile(#PB_Any, FileName)
If File
WriteData(File, *Mem, MemorySize(*Mem))
CloseFile(File)
FreeMemory(*Mem)
EndIf
EndProcedure