Autor Beitrag
Heiko
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: So 09.07.06 16:16 
Hallo,

da Delphi von Haus aus keine FileStream-Variante bietet, die UniCode(WideString) unterstützt, und ich die TnT-Controls auch nicht so mag, da diese auch nicht die Codestellen von Borland optimiert, die man ohne Probleme optimieren kann, habe ich eine eigene Klasse geschrieben, die nur das wichtigste in sich versammelt, was man zur bearbeitung von Dateien braucht. Des weiteren habe ich mit Absicht keine Fehlerbehandlung eingebaut, da es einem als fortgeschrittenem Entwickler oft anko***, wenn man Fehlermeldungen selber auch noch einmal abfangen muss, statt den eigentlichen Fehler abzufangen. (Also das keine Exception-Meldungen kommen).

Natürlich habe ich auch wieder einen Performancevergleich gemacht, um zu sehen, wie stark ich den Code optimieren konnte.

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
program Project1;

uses
  Windows, SysUtils, Classes, Dialogs,
  UniCodeFileStream in 'UniCodeFileStream.pas';

{$R *.res}

const
  TestFileSize = 10000000;

var
  FS: TFileStream;
  FSW: TFileStreamW;
  BigBuf: array of Byte;
  Buf: array[1..3of Char;
  i, j: integer;
  t, t1, t2: Cardinal;

begin
  t1:=0;
  t2:=0;
  SetLength(BigBuf, TestFileSize);
  for i:=0 to 19 do
  begin
    for j:=0 to TestFileSize-1 do BigBuf[i]:=random(256);
    t:=GetCurrentTime;
    FS:=TFileStream.Create('C:\Test.txt', fmCreate or fmOpenReadWrite);
    FS.Write(BigBuf[0], TestFileSize);
    FS.Position:=2;
    FS.Read(Buf[1], 2);
    FS.Position:=FS.Size-2;
    FS.Write(Buf[1], 2);
    FS.Size:=10;
    FS.Free;
    inc(t1, GetCurrentTime-t);

    for j:=0 to TestFileSize-1 do BigBuf[i]:=random(256);
    t:=GetCurrentTime;
    FSW:=TFileStreamW.Create('C:\Test.txt', fmCreate or fmOpenReadWrite);
    FSW.Write(BigBuf[0], TestFileSize);
    FSW.Position:=2;
    FSW.Read(Buf[1], 2);
    FSW.Position:=FSW.Size-2;
    FSW.Write(Buf[1], 2);
    FSW.Size:=10;
    FSW.Free;
    inc(t2, GetCurrentTime-t);
  end;
  ShowMessage('TFileStream  '+IntToStr(t1)+' ms'+#13#10+
              'TFileStreamW '+IntToStr(t2)+' ms');
end.


Die Ergebnis waren bei mir meistens für FileStream im Bereich von 4,7 Sek. und von meiner bei 4,2 Sek. (Der Test-Code ist auch dadurch ein bissl länger, da ich den verhindern musste, dass der Schreibcache einsetzt ;) ).

Die Unit befindet sich im Anhang und darf ohne Einschränkungen verwendet und modifiziert werden (bei den paar Codezeilen lohnt sich keine besondere Lizenz ;) ).

PS: Die Unit läuft diesmal auch gleich bei 95 etc. ;).
Einloggen, um Attachments anzusehen!


Zuletzt bearbeitet von Heiko am So 10.02.08 21:10, insgesamt 5-mal bearbeitet
Heiko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Mo 10.07.06 13:51 
Aso, eins hatte ich noch nicht dazu gesagt. Und zwar ist es ja für relative NEueinsteiger noch wichtig zu wissen, woran man erkennt, dass etwas fehlgeschlagen ist. Und zwar fehler beim öffnen erkennt man daran, dass das Handle=INVALID_HANDLE_VALUE ist und Fehlerneldung bekommt man über GetLastError. Wenn ich mich gerade nicht falsch erinnere, ist bei einem Fehler GetLastError=DWord(-1)
Heiko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Fr 11.08.06 20:37 
So V1.0.1 ist jetzt da. Ich habs um die Funktion Seek erweitert (MoveMethods: FILE_BEGIN, FILE_CURRENT, FILE_END)
Heiko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Di 12.12.06 18:29 
So, da ich das arbeiten mit "file of " (also das mit assignfile) nicht mag, habe ich jetzt noch readln und writeln hinzugefügt. Und zur Vereinfachung auch noch eine Property-Eigenschaft, die angibt, ob die Datei erfolgreich geöffnet wurde (Create Successful).
Neue Versionnummer ist damit 1.1.
Heiko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: So 10.02.08 21:09 
Lange ist es her, dass ein Update kam. Nun ist es soweit: V2.0.0 ist da.

Was ist neu?
Es existiert jetzt ein MemoryStream.
Aus diesem Grund gibt es jetzt auch eine Grundklasse - sprich ein Synonym zu TStream. TStream selber habe ich nicht als Grundklasse verwendet, da dort einige Dinge enthalten sind, die ich bisher nicht supporte (schreiben von Komponenten).

Wie ihr es gewohnt seit, gibt es auch ReadLn und WriteLn beim MemoryStream. Ihr habt also wieder einen Komfortgewinn gegenüber der Standardklasse ;).
Die Performance an sich ist die gleiche, wie beim DelphiStream - außer, ihr ladet Dateien bzw. speichert. Da bin ich meistens doch schneller ;).
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: Mo 11.02.08 15:56 
Ich sehe gerade. Das erste Feedback überhaupt und ich befürchte das wird nicht so erfreulich wie du gehofft hast. ;)

Also die Grundidee finde ich auf jeden Fall schon mal klasse. Derzeit habe ich zwar keine Verwendung dafür aber wenn, dann werde ich sicher darauf zurückgreifen.

Nur eine Sache stört mich ziemlich. "TStream selber habe ich nicht als Grundklasse verwendet". Um das mal sehr drastisch auszudrücken. Damit ist deine Klasse nur bedingt wirklich brauchbar. Denn TStream als Vorfahre heißt ja nicht, dass du alles unterstützten musst was TStream auch kann. Das sind eigentlich nur 6 Methoden und die hast du selber auch schon.

Der große Vorteil von TStream ist der, dass du deine Klasse zum Beispiel auch zum Laden eines Bitmaps oder JPEGs benutzen könntest. Was derzeit aber aufgrund der Klasseninkompatibilität einfach nicht möglich wäre. Aber eine Inkompatibilität die nicht nötig ist. Denn das ist ja eigentlich der Sinn hinter den Streams. Und dann könnte man deine Klasse für alles andere auch benutzten. Bzw gibt es von Delphi auch schon einen THandleStream, der alle Dateioperationen auf Basis eines Handles bereits implementiert.

_________________
Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
Heiko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Mo 11.02.08 19:21 
Hallo Lossy,

ja an den Punkt hatte ich auch gedacht, allerdings hatte ich nicht an die externen Teile, Image-dingens etc, gedacht. Bei denen müsste ich sogar nachgucken, ob die überhaupt eine Schnittstelle zu TStream haben.

Allerdings besteht trotzdem eine kompatibilität. Wenn man die Wirklich dafür verwenden will, reicht es, bei TStreamW als Vater nicht TObject sondern TStream hinzuschreiben und die abstrakten ProzeduHeader Read, Write und GetSize wegzunehmen. Von daher ist es nicht unbedingt ein Nachteil - denn wie oft verwendet Stream zur Weitergabe? Meistens nutzt man LoadFromFile. TImage bietet unter Picture z.B. keine Möglichkeit für eigene Streams ;).

Der Hauptsächliche Verwendungszweck ist also wirklich, dass einfache Bearbeiten von Streams.

Für die Zukunft, wenn ich mal wieder Zeit habe, wird der Stream dahingehend noch ausgebaut:
dass er erkennt, ob die Datei als UniCode-Datei gespeichert wurde oder nicht und dem entsprechend seine ReadLN/writeLn-Funktion anpasst und man beim schreiben auch entscheiden kann, ob UniCode und welche Zeilenumbrüche.
Als nächstes Hauptziel, wofür die darüberliegenden Etappenziele sind, ist dass eine eigen StringList und solch Kram, der also relativ langsam bei Delphi ist ;).

user profile iconLossy eX hat folgendes geschrieben:
Ich sehe gerade. Das erste Feedback überhaupt und ich befürchte das wird nicht so erfreulich wie du gehofft hast. ;)

Bei solchen Porjecten ist es immer schwierig, wo man ansetzten will ;). Eigentlich entstand das Project hier dadurch, dass ich mp3-Dateien etc. (hatte mal ein Projekt angefangen Tags von verschiedenen Formaten auszuelesen, was ich aber wegen diversen Lizenzen aufs Eis gelegt habe), auslesen wollte und dabei nicht unbedingt auf den TNTs basieren wollte, da ich bei denen eine gemischte Einstellung habe ;).

PS: Trotzdem Danke fürs Feedback :zustimm:
Silas
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 478

Windows XP Home
Delphi 2005, RAD Studio 2007, MASM32, FASM, SharpDevelop 3.0
BeitragVerfasst: Sa 05.04.08 15:04 
Moin Heiko,

ich habe mir gerade deine Unit angesehen, weil ich sie in meiner FastIniFiles-Unit verwenden möchte, wo du sie mir ja vor einiger Zeit vorgeschlagen hast.
user profile iconHeiko hat folgendes geschrieben:
Wenn man die Wirklich dafür verwenden will, reicht es, bei TStreamW als Vater nicht TObject sondern TStream hinzuschreiben und die abstrakten ProzeduHeader Read, Write und GetSize wegzunehmen.
Das funktioniert so nicht ganz, er schreit wegen den Properties, der Sichtbarkeit von einzelnen Methoden und noch ein paar andren Sachen.

Könntest du sie vielleicht einfach auf TStream umschreiben? Weil momentan mit TObject als Elternklasse kann ich wenig damit anfangen.

Danke!

_________________
Religionskriege sind nur Streitigkeiten darüber, wer den cooleren imaginären Freund hat ;-)
Heiko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Sa 05.04.08 15:10 
Hallo Silas,

ist geplannt. Allerdings mache ich gerade noch BwInf und unsere Schul-HP. Von daher komme ich auf der Baustelle momentan da nicht wirklich voran. Das Problem besteht darin, dass es doch größere Verändeurngen braucht, denn ich arbeite an einigen Stellen auf Basis von Cardinal, wo Delphi Int64 nimmt. Da muss ich nen paar Stellen mir nochmal genauer angucken ;).

Allerdings: Bis Sommerferien werde ichs ja bestimmt geschafft haben, hab ja am 21.04. meinen letzten Schultag ;).
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mi 16.04.08 16:27 
Statt GetSize muss Seek angepasst werden ... (Zumindest laut VCL-Standard).

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Heiko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Do 08.05.08 20:32 
Nur mal so als Zwischenstand: die neue Version basiert vollständig auf TStreams - sprich wer bisher meine eingebaut hat, muss ggf. kleines bissl ummoddeln. Der Gesamte kurz wird ein bisschen kürzer - vermutlich zu lasdten der Performance, da Borland ne Menge Schrott drin hat ;).

Beispiel:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
{ Deflect 32 seek requests to the 64 bit seek, if 64 bit is implemented.
  No existing TStream classes should call this method, since it was originally
  abstract.  Descendent classes MUST implement at least one of either
  the 32 bit or the 64 bit version, and must not call the inherited
  default implementation. }

Nach dem ich solche Stellen gefunden habe, lasse ich die Unit meistens 2-3 Tage liegen - Borland verdirbt einem da echt die Lust :evil: .

In Summe bin ich jetzt bei schätzungswiesen 75%. Der FileStream ist imhop komplett, aber beim MemoryStream meckert er noch genug Quelltext an. Ich hoffe, dass ich die nächsten Tage damit endlich mal fertig werde (beim MemoryStream brauche ich ja kaum noch auf den Vorgänger achten ;) ).

PS: Dieser Beitrag ist eigentlich nur dazu da, um zu zeigen, was man in Borlands Units findet ;).