![]() |
TMemFileStream - Ein Zwitter aus TMemoryStream und TFileStream
Falls es mal jemand gebrauchen kann hier mein TMemFileStream
Delphi-Quellcode:
unit uMemFileStream;
{ ********************************************************************** Version: 1.1 (2010-11-01) ---------------------------------------------------------------------- TMemFileStream Dieser Stream verbindet die Vorteile von TMemoryStream und TFileStream Wenn der SystemCache ausreicht befindet sich der Stream komplett im RAM und auch nur dort. Erst wenn der SystemCache die Datenmenge nicht mehr speichern kann, wird der Stream physisch auf den Datenträger geschrieben. Der Vorteil bei der Verwendung, man braucht sich nicht mehr darum zu kümmern, ob das System genug RAM-Speicher für den Stream zur Verfügung hat. Die Grenze ist hierbei der freie Speicher auf dem Datenträger. Ein System mit ausreichend Hauptspeicher profitiert automatisch, weil der Stream auch direkt im Hauptspeicher verwaltet wird. Ein TMemoryStream ist allerdings deutlich performanter im Zugriff Ein TFileStream ist langsamer im Zugriff Hierbei handelt es sich um eine umgeschriebene TFileStream-Klasse ---------------------------------------------------------------------- Historie: 2010-11-01 Version 1.1 + SetSize 2010-11-01 Version 1.0 ********************************************************************** } interface uses Classes; type { TMemFileStream class } TMemFileStream = class( THandleStream ) strict private FFileName : string; public procedure SetSize( const NewSize : Int64 ); override; procedure SaveToStream( const Stream : TStream ); procedure SaveToFile( const FileName : string ); procedure LoadFromStream( const Stream : TStream ); procedure LoadFromFile( const FileName : string ); constructor Create( const APath : string = '' ); destructor Destroy; override; end; implementation uses Windows, SysUtils, RTLConsts; const TEMP_FILE_PREFIX = 'mfs'; // Ermittelt das TEMP-Verzeichnis function GetDirTemp : string; var BufSize : Cardinal; begin SetLength( RESULT, MAX_PATH ); BufSize := Windows.GetTempPath( Length( RESULT ), PChar( RESULT ) ); SetLength( RESULT, BufSize ); RESULT := ExcludeTrailingPathDelimiter( PChar( RESULT ) ); end; function GetTempFileName( const APath : string; const APrefix : string = TEMP_FILE_PREFIX ) : string; var NewTemp : array [ 0 .. MAX_PATH ] of Char; MPath : string; begin FillChar( NewTemp, SizeOf( NewTemp ), #0 ); MPath := IncludeTrailingPathDelimiter( APath ); Windows.GetTempFileName( PChar( MPath ), PChar( Copy( APrefix, 1, 3 ) ), 0, @NewTemp ); RESULT := NewTemp; end; function FileCreateTemp( const FileName : string; Mode : LongWord; Rights : Integer ) : Integer; const ShareMode : array [ 0 .. 4 ] of LongWord = ( 0, 0, FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE ); begin RESULT := -1; if ( Mode and $F0 ) <= fmShareDenyNone then RESULT := Integer( CreateFile( PChar( FileName ), // Zugriff natürlich lesend und schreibend GENERIC_READ or GENERIC_WRITE, // wie auch immer ShareMode[ ( Mode and $F0 ) shr 4 ], // keine SecurityAttributes nil, // auf jeden Fall erzeugen, auch wenn der Dateiname schon existiert CREATE_ALWAYS, // Temporäre Datei // Daten werden nur dann physisch auf den Datenträger geschrieben, // wenn der Cache nicht mehr ausreicht FILE_ATTRIBUTE_TEMPORARY or // nicht indizieren // die Datei verschwindet ja eh wieder und würde somit nur Zeit kosten FILE_ATTRIBUTE_NOT_CONTENT_INDEXED or // verstecken // braucht darum auch niemand zu sehen FILE_ATTRIBUTE_HIDDEN or // am Ende automatisch löschen // und damit keinen Datei-Müll zurücklassen // Wir sind ja saubere Schweinchen FILE_FLAG_DELETE_ON_CLOSE, // keine Template benutzen 0 ) ); end; { TMemFileStream } constructor TMemFileStream.Create( const APath : string ); var Path : string; AFileName : string; begin if APath = '' then // Temp-Pfad holen Path := IncludeTrailingPathDelimiter( GetDirTemp ) else Path := IncludeTrailingPathDelimiter( APath ); // eindeutigen Dateinamen für eine temp. Datei holen AFileName := GetTempFileName( Path ); // temp. Datei erzeugen inherited Create( FileCreateTemp( AFileName, fmShareExclusive, 0 ) ); // gab es kein Handle, dann haben wir einen Fehler if FHandle = INVALID_HANDLE_VALUE then // tue Gutes und sprich davon :D raise EFCreateError.CreateResFmt( @SFCreateErrorEx, [ ExpandFileName( AFileName ), SysErrorMessage( GetLastError ) ] ); FFileName := AFileName; end; destructor TMemFileStream.Destroy; begin if FHandle <> INVALID_HANDLE_VALUE then FileClose( FHandle ); inherited Destroy; end; procedure SetSize( const NewSize : Int64 ); begin inherited SetSize( NewSize ); end; procedure TMemFileStream.LoadFromFile( const FileName : string ); var Stream : TFileStream; begin Stream := TFileStream.Create( FileName, fmOpenRead or fmShareDenyWrite ); try LoadFromStream( Stream ); finally Stream.Free; end; end; procedure TMemFileStream.LoadFromStream( const Stream : TStream ); begin Stream.Position := 0; SetSize( Stream.Size ); Position := 0; CopyFrom( Stream, Stream.Size ); end; procedure TMemFileStream.SaveToFile( const FileName : string ); var Stream : TFileStream; begin Stream := TFileStream.Create( FileName, fmCreate or fmShareExclusive ); try SaveToStream( Stream ); finally Stream.Free; end; end; procedure TMemFileStream.SaveToStream( const Stream : TStream ); var MPosition : Int64; begin MPosition := Position; Position := 0; Stream.CopyFrom( Self, Size ); Position := MPosition; end; end. |
AW: TMemFileStream - Ein Zwitter aus TMemoryStream und TFileStream
Auf SetSize reagierst du nicht, also da sollte ja die Dateigröße angepaßt werden.
Wieso schneidest du das Ende des übergebenen Pfades ab? Es würde mir nicht gefallen, wenn ein anderer Pfade verwendet würde, als ich angegeben hab.
Delphi-Quellcode:
Ansonsten sieht es gibt aus, vorallem FILE_ATTRIBUTE_TEMPORARY und FILE_FLAG_DELETE_ON_CLOSE. :thumb:
if APath = '' then
// Temp-Pfad holen Path := GetDirTemp else Path := IncludeTrailingPathDelimiter( APath ); Als kleinen Schönheitsfehler, das Const in
Delphi-Quellcode:
ist unnötig
const Stream : TStream
und im Prinzip auch "falsch", da du den Stream, also .Position kurzzeitig veränderst. |
AW: TMemFileStream - Ein Zwitter aus TMemoryStream und TFileStream
Zitat:
Zitat:
Zitat:
Zitat:
Delphi-Quellcode:
schützt doch nur davor, dass die übergebene Referenz nicht verändert wird. Die Properties erben ja nicht den
const
Delphi-Quellcode:
Status, oder :gruebel:
const
|
AW: TMemFileStream - Ein Zwitter aus TMemoryStream und TFileStream
[edit]
Wegen dem SetSize ... hab grad gesehn, daß THandleStream das doch schon drin hat. Hatte was im Kopf, daß dieses noch fehlt, aber das war nur beim TStream so, wo nur ein paar Dummymethoden vorhanden sind, welche eine Exception auslösen, wenn nicht mindestens eine der beiden SetSize-Methoden überschrieben wurden. :oops: [/edit] Jupp, CONST schützt nur vorm Ändern der Instanzvariable, bzw. vom Anlegen einer Kopie seitens Delphi. Bei Klasseninstanzen gibt es keinen Unterschied, wenn man CONST verwendet oder nicht, darum schreiben es viele auch nicht mit hin. Nja, Const in einer Deklaration impliziert eine Nichtveränderung des Wertes, aber du Änderst schon den Inhalt des Objektes ... darum auch nur "Schönheitsfehler". Mit und ohne CONST ist es formal korrekt (also im Bezug auf den Parameter), aber "logisch" kann man sich da gerne streiten. :angle: Ich persönlich nutzt manchmal die Tatsache, daß hier mit und ohne CONST von Delphi gleich behandelt wird gerne mal aus. > ohne CONST, quasi als implizites VAR, bei Veränderungen am Objekt > mit CONST, wenn nix verändert wird > und VAR, wenn die Instanzvariable verändert wird |
AW: TMemFileStream - Ein Zwitter aus TMemoryStream und TFileStream
Gibt es dafür
Delphi-Quellcode:
keine Konstante? Und wenn nicht wäre es lesbarer, wenn man eine definieren würde, weil ich weiß aus dem Kopf nicht, was die Zeile macht.
ShareMode[ ( Mode and $F0 ) shr 4 ]
|
AW: TMemFileStream - Ein Zwitter aus TMemoryStream und TFileStream
ShareMode ist die Konstande.
Der Mode-Parameter für TFileStream enthält kodiert 2 Werte. > Zugriffsrechte wie GENERIC_READ und GENERIC_WRITE) > Sharingrechte wie FILE_SHARE_READ und FILE_SHARE_WRITE Das and/shr extrahiert nun den Anteil für die Sharingrechte (Mode and $F0). Die Zugriffsrechte (Mode and $0F) werden hier nicht ausgewertet, da Eigene genommen werden. Aber wenn man sich das richtig überlegt, dann braucht man dieses garnicht, da der Dateiname jedesmal dynamisch erstellt wird, wenn man einen TMemFileStream erstellt und es keinen sicheren Weg gibt, um an den Dateinamen eines TMemFileStream ranzukommen. > Also entweder man speichert diesen Namen und bietet eventuell noch eine Möglichkeiten auch direkt auf einen bestehenden TMemFileStream, bzw. auf dessen Datei zuzugreifen (also einen weiteren TMemFileStream direkt auf eine bestehende Datei zu erstellen). > Oder man verweigert lieber sämtliche Fremdzugriffe, indem man garkeine Sharingrechte angibt. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:19 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz