![]() |
Stream Ableitung, mit Eigenschaften von File- und Memstream?
Hi, ich bin auf der suche nach einer Art intelligentem Stream, der von TStream abgeleitet ist, und zunächst die selben eigenschaften hat wie ein Memorystream. Wird aber eine bestimmte Größe im Speicher erreicht, soll er die Daten praktisch auslagern und dann so funktionieren wie ein Filestream. (es wird eine temporäre Datei erstellt).
Warum ich nicht direkt einen Filestream benutzte? Ich bräuchte eine Art filestream, in den man per Write(Buffer, count) daten schreiben kann, ohne die Originaldatei zu verändern. Nun könnte man auf die Idee kommen, einfach eine Kopie der Originaldatei anzulegen. Aber das kann bei großen Dateien ja schonmal ewig dauern und viel Zeit kosten. Dafür habe ich hier mal ein bisschen was rumexperimentiert, ist alles noch was unschön programmiert, sind erst erste versuche: Ist mein Stream kleiner als 5mb, wird er im speicher gehalten. Danach wird eine temporäre Datei (0.part 1.part usw) erzeugt, in welche die Daten geschrieben werden und dann per Filestream benutzt werden. Wird ein Stream aus einer vorhandenen Datei geladen, so ist sie "protected". D.h. schreibt man per write neue Daten in den Stream, werden nur die änderungen in einem seperaten Stream gespeichert (ChangeSave). Ich hab den Code mal angehängt. Vielleicht kann mir jemand ein paar Tipps geben, wie das ganze etwas "schöner" zu programmieren ist. Konkret hänge ich bei dem "read" befehl. Ich versuche grade aus dem ChangeSave (also den gemachten Änderungen) und dem Originalfilestream wieder den gewünschten Stream zusammen zu bauen. Also bitte nicht hauen, weils unsauber geschrieben ist...
Delphi-Quellcode:
Bin für alle Vorschläge dankbar.unit Unit2; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs; type TExtendedStream = class(TStream) Constructor Create(OpenFromFilename:string); function write(Const Buffer;Count:integer):integer; function read(var Buffer;Count:integer):integer; private { Private-Deklarationen } aStream:TStream; ChangeSave:TExtendedStream; protect:boolean; inMemory:boolean; swapsize:integer; public Size:int64; Position:int64; { Public-Deklarationen } end; implementation function GetTempFileName(TempDirectory:String):string; var filename:string; i:integer; begin i:=0; filename:=inttostr(i)+'.part'; while fileexists(TempDirectory+filename) do begin inc(i); filename:=inttostr(i)+'.part'; end; result:=TempDirectory+filename; end; function GetFileSize(szFile: PChar): Int64; var fFile : THandle; wfd : TWIN32FINDDATA; begin result := 0; if not FileExists(szFile) then exit; fFile := FindFirstfile(pchar(szFile), wfd); if fFile = INVALID_HANDLE_VALUE then exit; result := (wfd.nFileSizeHigh * (Int64(MAXDWORD) + 1)) + wfd.nFileSizeLow; windows.FindClose(fFile); end; constructor TExtendedStream.Create(OpenFromFilename:string); begin swapsize:=5242880; ChangeSave:=nil; if OpenFromFilename='' then begin aStream:=TMemoryStream.Create; inMemory:=True; Position:=0; Size:=0; protect:=False; end else if fileexists(OpenFromFilename) then if GetFileSize(pChar(OpenFromFilename))<swapsize then begin aStream:=TMemoryStream.Create; TMemoryStream(aStream).LoadFromFile(OpenFromFilename); inMemory:=True; protect:=False; Position:=0; Size:=0; end else begin aStream:=TFilestream.Create(OpenFromFilename,fmOpenRead); inMemory:=False; protect:=true; Position:=0; Size:=astream.Size; end; end; function TExtendedStream.write(Const Buffer;Count:integer):integer; var dummystream:TMemorystream; len:integer; begin if inMemory=true then if sizeof(Buffer)+TMemorystream(aStream).size<swapsize then begin TMemorystream(aStream).Position:=self.Position; TMemorystream(aStream).Write(Buffer,count); size:=TMemorystream(aStream).Size; position:=TMemorystream(aStream).position; end else begin //swapen dummystream:=TMemorystream(aStream); aStream:=TFilestream.Create(GetTempFileName('C:\'),fmcreate); dummystream.Position:=0; Tfilestream(aStream).CopyFrom(dummystream,dummystream.size); freeandnil(dummystream); inMemory:=False; protect:=false; Tfilestream(aStream).Position:=self.Position; Tfilestream(aStream).Write(Buffer,count); size:=Tfilestream(aStream).Size; position:=Tfilestream(aStream).position; end else //inMemory=false if not protect then begin TFileStream(aStream).position:=position; TFileStream(aStream).Write(Buffer,count); size:=Tfilestream(aStream).Size; position:=Tfilestream(aStream).position; end else begin //in Memory=false protect=true if ChangeSave=nil then begin ChangeSave:=TExtendedStream.create(''); ChangeSave.Position:=0; end; ChangeSave.Position:=ChangeSave.Size; ChangeSave.write(self.Position,sizeof(self.Position)); len:=sizeof(buffer); ChangeSave.write(len,sizeof(len)); ChangeSave.write(Buffer,Count); end; end; function TExtendedStream.read(var Buffer;Count:integer):integer; var dummystream:TMemorystream; pos,len:integer; rel_start,rel_end:integer; begin if inMemory=true then begin TMemorystream(aStream).Position:=self.Position; TMemorystream(aStream).read(Buffer,count); position:=TMemorystream(aStream).position; end else //inMemory=false if not protect then begin TFileStream(aStream).position:=position; TFileStream(aStream).Read(Buffer,count); position:=Tfilestream(aStream).position; end else begin //in Memory=false protect=true if ChangeSave<>nil then begin ChangeSave.Position:=0; ChangeSave.read(pos,sizeof(pos)); ChangeSave.read(len,sizeof(len)); rel_start:=position-pos; rel_end:=(position+count)-(pos+len); if rel_start>=0 then if rel_end>=0 then //readstream komplett in Changestream begin ChangeSave.Position:=ChangeSave.Position+rel_start; ChangeSave.read(Buffer,count); ChangeSave.Position:=ChangeSave.Position+rel_end; end else begin //Readstream Ende liegt außerhalb von Changestream ChangeSave.Position:=ChangeSave.Position+rel_start; ChangeSave.read(Buffer,count+rel_end); {hier hänge ich grade etwas} end; end; end; end; end. Grüße Alleinherrscher |
Re: Stream Ableitung, mit Eigenschaften von File- und Memstr
Die sinnvollste Variante ist es einen MemoryStream zu nehmen. Denn sobald die Größe nicht mehr in den normalen Ram passt lagert Windows sowieso in das SwapFile aus. Warum gerade diese Größe (5MB)?
[OT] folgendes solltest du vermeiden und dir gar nicht erst angewöhnen
Delphi-Quellcode:
[/OT]
if inMemory=true then
[Edit] Ich finde die Idee recht interessant einen "ReadOnly" Stream zu haben und nur die Änderungen gesondert zu speichern. Wenn du nichts dagegen hast würde ich die Idee gern versuchen umzusetzen. |
Re: Stream Ableitung, mit Eigenschaften von File- und Memstr
Ja, im moment Arbeitet mein Programm mit einem MemoryStream. Allerdings dauert das auslagern so ewig.
Beispiel: Ich lade manchmal relativ große Dateien in den Memorystream. Dabei macht ja windows dann nix anderes als Auslangern, also im Grunde "nochmal ne Kopie der Daten in der Auslangerungsdatei" anlegen. Wenn ich jetzt aber die eigenschaften eines Filestreams hätte, müsste nix nochmal ausgelagert werden, alles ginge ganz fix und ich wäre glücklich. Problem nur: Ich muss aber leider Daten in den Stream schreiben, weswegen dadurch meine Originaldateien kaputt gehen würden. Wichtig ist mir noch: Wenn ich jetzt nur die Änderungen speichere, müssten die sich auch von selbst in temporäre Dateien schreiben, falls sie Größer als die swapsize werden. Hm...ich finde es ist irgendwie relativ schwer zu beschreiben... 5mb hab ich einfach mal als Beispiel genommen, du kannst ja auch meinetwegen 50 mb nehmen....vollkommen egal... solange es halt noch in dem Ram passt... Klar kannst du dich mal dran versuchen, wie gesagt, bin für jede Idee dankbar ;) |
Re: Stream Ableitung, mit Eigenschaften von File- und Memstr
Nette Stream-Idee. Vielleicht mache ich eine Variante fuer die JCL. Da haben wir ein Sortiment abseitiger, aber nuetzlicher Streams.
Fuer diesen Stream ist es wichtig das er die Datei in der richtigen Directory anlegt und das im Konstruktor erledigt, damit ein Problem bei der Dateierstellung nicht erst spaeter auftritt. Weiss jemand wie das bei Vista geregelt ist? Ist es sichergestellt das die Directory in der Environment-Variable TEMP auch fuer alle Benutzer schreibbar ist? |
Re: Stream Ableitung, mit Eigenschaften von File- und Memstr
Schätze mal, dass Vista %Temp% immer noch kennt.
Danke, Robert für das Lob ;) Mein Hauptproblem im Moment ist, dass ich nicht weiß wie ich "zwei Buffer" zusammenfasse: Beispiel: ![]() TExtendetStream.Position:=110; TExtendetStream.Read(Buffer,150); Dann muss ich mir meinen Buffer aus dem Buffer vom Changestream und dem vom Originalstream zusammenbasteln...wie mache ich das am besten? |
Re: Stream Ableitung, mit Eigenschaften von File- und Memstr
Das Problem ist nicht das Vista TEMP kennt, sondern ob die Directory sicher fuer alle Benutzer schreibbar ist. Ich habe schon viel von den MS-Programmierern erlebt und bin auf alles gefasst. Windows hatte nie ein so weitgehendes Konzept von Temporaerdateien wie Unix.
Bei deinem Pufferproblem habe ich gerade keine Lust dir zu helfen. Morgen vielleicht. |
Re: Stream Ableitung, mit Eigenschaften von File- und Memstr
Hallo,
warum sollte das Temp-Verzeichnis für alle User beschreibbar sein? Jeder User hat doch sein eigenes Temp-Verzeichnis. Unter Vista ist das "C:\Users\<UserName>\AppData\Local\Temp", unter XP "C:\Dokumente und Einstellungen\<UserName>\Lokale Einstellungen\Temp". Das Verzeichnis "C:\Windows\Temp" erlaubt aber immer noch allen Benutzern das Anlegen von Dateien. Gruß xaromz |
Re: Stream Ableitung, mit Eigenschaften von File- und Memstr
Ich habe gerade gesehen das jemand gerade an JclBufferedStream arbeitet. Da duerfte diese Idee ziemlich genau dazupassen. Ich sag ihm mal bescheid.
|
Re: Stream Ableitung, mit Eigenschaften von File- und Memstr
Hey, Robert! Dankeschön für deine Mithilfe!
Also wenn ich das User Account Control System von Vista richtig verstanden habe (habs nur überflogen) können Benutzer und Anwendungen in die zum Benutzerprofil gehörigen Ordner natürlich ohne Beschränkung schreiben und lesen, also auch in die entsprechenden Temp Folder. Für alle anderen Zugriffe auf Systemordner u.Ä. legt Windows für jeden User eine Art virtuelles Dateisystem an. Hier ein paar Infos dazu, die hoffentlich weiterhelfen: ![]() |
Re: Stream Ableitung, mit Eigenschaften von File- und Memstr
Zu Beitrag #5
Am einfachsten wäre es wenn man sich eine Liste macht wo die ganzen geänderten Buffer aufgeführt sind mit fester Größe. Wird etwas geschreiben suchst du also einfach ob der Bereich schon in der Liste der geänderten Teile ist. Wenn ja dann wird in dem teil gearbeitet. Wenn nicht wird der angelegt |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:10 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