AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Projekte Virtual Memory Stream
Thema durchsuchen
Ansicht
Themen-Optionen

Virtual Memory Stream

Ein Thema von himitsu · begonnen am 14. Apr 2010 · letzter Beitrag vom 15. Apr 2010
Antwort Antwort
Benutzerbild von himitsu
himitsu Online
Registriert seit: 11. Okt 2003
Tachchen,

ich weiß nicht, ob es irgendwo schon etwas Gleichartiges gibt,
aber da ich nichts fand [add](vergessen, daß es hier was kleines gab)[/add] und sowas brauchte, ist Dieses entstanden.
Nun hab ich's halt auch mal aus meinem Projekt ausgebaut und da isses.

Hier erstmal der wichtigste Header:
(ist nicht viel, aber so viel braucht man ja auch nicht)
Delphi-Quellcode:
TVMSState = (msNone, msCopy, msCopyAndFreeMem, msOnlyFree);
TVMSOnResize = Procedure(Sender: TVirtualMemoryStream; RequiredSize: LongInt;
  Var Memory: Pointer; Var MaxSize: LongInt; Var State: TVMSState) of Object;
TVirtualMemoryStream = Class(TStream)
Private
  FMemory: Pointer;
  FMaxSize, FSize: LongInt;
  FPosition: LongInt;
  FOnResize: TVMSOnResize;
  FTemp: Record P: Pointer; I: LongInt; S: TVMSState; O: TVMSOnResize; End;
  Procedure OnChangeMemory(Sender: TVirtualMemoryStream; RequiredSize: LongInt;
    Var Memory: Pointer; Var MaxSize: LongInt; Var State: TVMSState);
Protected
  Function GetSize: Int64; Override;
  Procedure SetSize(NewSize: LongInt); Overload; Override;
  Procedure SetSize(Const NewSize: Int64); Overload; Override;
  Procedure SetMem(Memory: Pointer; MaxSize: LongInt); Virtual;
Public
  Constructor Create(Memory: Pointer; MaxSize: LongInt; Size: LongInt = 0);
  Destructor Destroy; Override;

  Function Read (Var Buffer; Count: LongInt): LongInt; Override;
  Function Write(Const Buffer; Count: LongInt): LongInt; Override;
  Function Seek (Offset: LongInt; Origin: Word): LongInt; Overload; Override;
  Function Seek (Const Offset: Int64; Origin: TSeekOrigin): Int64; Overload; Override;

  Procedure SetPointer (Memory: Pointer; MaxSize: LongInt; Size: LongInt = 0);
  Function ChangeMemory(NewMemory: Pointer; NewMaxSize: LongInt;
    OldMemState: TVMSState = msCopyAndFreeMem): Pointer{old Memory};

  Property Memory: Pointer Read FMemory;
  Property MaxSize: LongInt Read FMaxSize;
  Property OnResize: TVMSOnResize Read FOnResize Write FOnResize;
End;
Es handelt sich im Prinzip um eine Art MemoryStream, welcher allerdings keine eigene Speicherverwaltung besitzt.

TStaticMemoryStream wird beim Erstellen ein Speicherbereich und dessen Größe mitgegeben
und nun kann man auf diesen Speicher über den Stream zugreifen.

Ist dem OnResize-Ereignis etwas zugewiesen, macht die Klasse Selbe, allerdings kann hier der Speicher nachträglich getauscht, bzw in dessen Größe verändert werden.
So kann man den Stream mit jeder Art von Speicherstrukturen versorgen und diese sogar dynamisch ändern lassen, wenn es nötig ist.

Tja, und nun noch ein kleines Beispielprojektchen.

Delphi-Quellcode:
Program Project1;

Uses Classes, Dialogs, StatMemStream;

Var Data: Array[0..1023] of Byte;
  Stream: TStream;
  I: LongInt;
  S: AnsiString;

Begin
  Move(PAnsiChar('Das ist ein ')^, Data, 12);
  Stream := TStaticMemoryStream.Create(@Data, SizeOf(Data), 12);
  Stream.Position := 12;
  i := $74736554;
  Stream.WriteBuffer(i, 4);
  i := $002E;
  Stream.WriteBuffer(i, 2);
  Stream.Position := 0;
  SetLength(S, Stream.Size);
  Stream.ReadBuffer(S[1], Length(S));
  Stream.Free;
  ShowMessage(S);
  ShowMessage(PAnsiChar(@Data));
End.
Ich glaub der Speicher-Callback war nicht sonderlich gut geglückt und ich werde ihn wohl noch auftrennen (quasi in Callbacks für Get, Free und Realoc).


Der Stream ist natürlich nicht threadsicher (wie viele andere Streams auch), aber im Notfall kann man ja mehrere Streams auf den selben Speicher zeigen lassen.

[edit]
- der OnResize-Callback wurde etwas geändert
- die beiden Klassen wurden vereint
- und die Property wurden in einer Custom-Klasse versteckt
Angehängte Dateien
Dateityp: pas vmemstream_121.pas (9,6 KB, 56x aufgerufen)
Dateityp: dpr project1_213.dpr (2,6 KB, 39x aufgerufen)
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
 
Benutzerbild von Neutral General
Neutral General

 
Delphi 10.2 Tokyo Professional
 
#2
  Alt 14. Apr 2010, 23:50
Hi,

Habs mir noch nicht angeguckt. Schau es mir vllt. mal morgen an (jetzt erstmal schlafen gehn^^), aber es gibt sowas schon:

TVirtualStream:
http://www.delphipraxis.net/internal...059&highlight=

Michael
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

 
Delphi 12 Athens
 
#3
  Alt 15. Apr 2010, 00:40
ups, den virtuellen hab'sch ganz vergessen.
  Mit Zitat antworten Zitat
Benutzerbild von SirThornberry
SirThornberry

 
Delphi 2006 Professional
 
#4
  Alt 15. Apr 2010, 08:14
Du hast vergessen den originalen Constructor zu überschrieben, oder?
Was passiert wenn jemand diesen aufruft? Deine privaten Variablen bleiben uninitialisiert und eine aussagekräftige Fehlermeldung kommt auch nicht. Die Fehler kommen erst wenn man später auf die jeweiligen Methoden zugreift.

[Edit]
Ich nehme meine Aussage zurück. Ich habe gerade bei TFileStream geschaut und da ist es genauso. Und wenn man versucht den Standardconstructor aufzurufen kommt ein Fehler das es keinen Constructor gibt der mit diesem übereinstimmt.
Delphi-Quellcode:
var
  lStream: TFileStream;
begin
  lStream := TFileStream.Create(); // = There is no overloaded Version of Create that can be called with these arguments
Das verwirrt mich allerdings denn letzendlich ist TFilestream über zig Umwege von TObject abgeleitet und dort existiert eben jener Constructor Warum funktioniert das also nicht?!
Jens
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

 
Delphi 12 Athens
 
#5
  Alt 15. Apr 2010, 08:27
Der Original-Constructor würde das Selbe machen, wie .Create(nil,0) .
Er verhält sich also wie ein leerer Stream, mit der Maximalgröße von 0.
Eine unbeabsichtigte Zugriffsverletzung/Fehler sollte nicht auftreten, denn immerhin werden die Felder mit 0 initialisiert.

Die einzigen Fehler, welche auftreten können, wären
- ein ungültiger Pointer
- MaxSize größer als der Speicherblock

Ich könnte zwar prüfen ob der Speicherblock lesbar/schreibbar ist, aber da ich nicht sicherstellen kann, daß der Speicherblock wirklich für diesen Zugriff gedacht ist, hab ich diesbezüglich keine Prüfung verbaut.
  Mit Zitat antworten Zitat
Benutzerbild von SirThornberry
SirThornberry

 
Delphi 2006 Professional
 
#6
  Alt 15. Apr 2010, 08:28
Stimmt. Ich bin derzeit insgesamt wohl etwas verwirrt
Jens
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

 
Delphi 12 Athens
 
#7
  Alt 15. Apr 2010, 19:36
Ups, jetzt hätt ich beinah vergessen zu antworten.

@Bärchen: macht ja nix http://fnse.de/S05/1L9.gif


Joar und was gibt es sonst noch.
Hab's doch noch schnell etwas geändert
und hab mir mal des Generals Klassen-Name gemopst.

Aber Aufgrund der besseren Bereichsprüfung laß ich meinen Code dennoch hier.
  Mit Zitat antworten Zitat
Benutzerbild von Neutral General
Neutral General

 
Delphi 10.2 Tokyo Professional
 
#8
  Alt 15. Apr 2010, 19:42
Zitat von himitsu:
und hab mir mal des Generals Klassen-Name gemopst.


Copyright, Urheberrecht und so! TVirtualStream™ !

Michael
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:11 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz