![]() |
Delphi-Version: 5
Base64/ Mime für Dateien
So, 2 Dinge brauche ich:
Datei -> base64-String Datei -> base64-Datei und zurück. Wie kann man Dateien am sinnvollsten/schnellsten/besten [Stream/sonstwie] mime codieren: Ich möchte eine große (ca.80 MB) Datei gerne in base64 sichern/umwandeln. Unüblich ich weiß. Doch das dauerte mit diversen anderen units, die ich über die Jahre mal gefunden habe sonst teilweise für 1 MB StringDaten schon extrem lange. Erst hatte ich mit der DEC 5.2 Funktion herumgespielt, weil ich gesehn hatte, daß Hagen die Funktion dort auch eingebaut hat. Allerdings, wie mir scheint eher nur für Strings (z.B. den Salt; evtl. auch für den Cryptotext). Oder? Ich hab dann nochmal gesucht und die Unit von Sakura (wieder)gefunden. ![]() Diese oder eine ähliche hab ich vor Jahren schon mal abgespeichert und in einem älteren Projekt eingebunden, fand aber später mal in meinen Projekten, daß die in DEC eingebaute Routine[mime?] für einige tausend/Mio Bytes irgendwie schneller war. So, nun wollte ich dennoch diese auch verwenden, weil die mit Streams zurechtzukommen scheint, hab aber generelle Probleme damit/ u.mit Streams. (bin auch noch "neu" mit Delphi/pascal) Streams - dazu hab ich mir mittlerweile was durchgelesen - aber ich kann doch eigentlich nicht in BufferTeilen in eine Base64 Procedur reinschieben - das gibt doch sicher total andere Eegebnisse, als von einem kontinuierlichen Strom? Dann hätte ich ja unterbrochene, einzeln b64 codierte Stringabschnitte. Wie mach ich das am besten? "Datei als base64-String" wäre evtl. auch noch gut, für kleinere Dateien. müßte doch auch gehen?
Delphi-Quellcode:
var
OUTStrom, strm : TFileStream; FN: String; Buffer:array[0..7] of byte; Buffer2:array[0..7] of byte; begin begin FN := 'C:\neu.txt'; // 5 MB groß strm:=TFileStream.Create(FN,fmOpenRead); if not FileExists(FN + 'UUX') then FileCreate(FN+ 'UUX'); OUTStrom:=TFileStream.Create(FN + '_ENC' ,fmOpenWrite or fmShareDenyNone); strm.Seek(0,soFromBeginning); OUTStrom.Seek(0,soFromBeginning); Base64Encode(Strm, 8, OUTStrom); strm.Free; OUTStrom.Free; end; Hab das einfach mal so versucht, mit dem, was ich mir über Streams so zusammengoogeln konnte. Die Buffergröße ist ... einfach mal geschätzt gewählt. Ob die sinnvoll ist, weiß ich nicht. Jedenfalls bricht das Programm bei Durchführung einfach ab und bleibt im CPU Diassembler stehen: datatype missalignment at 0x77b4d7e8. Naja, vielleicht wißt Ihr ja, wie man das insgesamt besser lösen könnte. Ich kenn mich mit Streams nicht so aus. Anfangs hatte ich darum eine Stringlist.loadfromFile('neu.txt') als Speicher verwenden wollen, aber das ging auch nicht, da dann nur die erste, kurze Zeile verwendet wurde. Eine Suche hier im Forum und entwEcke nach Datei und Mime oder base64 brachte vieles, aber auch viele Threads, in denen die das mit Indy lösten. Zudem hab ich aber Delphi 5. (64 Bit brauch ich nicht) Vielleicht hat jemand eine Idee und einen Moment Zeit zu antworten. (Der umgekehrten Weg (b64Decode) ist hoffentlich genauso einfach.?) Danke. |
AW: Base64/ Mime für Dateien
Warum nutzt Du nicht die TIdEncoderMIME Klasse der Indy-Unit IdCoderMIME? Damit geht es recht einfach und schnell.
Delphi-Quellcode:
Bei mir dauern 80 MB etwas mehr als 4 Sekunden.
FileToEncode := TFileStream.Create(aFileNameSource, fmOpenRead);
FileAsBase64 := TFileStream.Create(aFileNameDest, fmCreate); try idCodec64.Encode(FileToEncode, FileAsBase64); finally FileAsBase64.Destroy; FileToEncode.Destroy; end; ...:cat:... |
AW: Base64/ Mime für Dateien
Zitat:
äh ja, weil Du (EDIT: damals) selbst geschrieben hast: Zitat:
![]() Das hab ich ernst genommen. :) und langsame units kannte ich schon, die hab ich reichlich im Netz gefunden. (wohl eher für kurze Strings geeignet.) Und da dachte ich mir ... wenn schon ... dann eine Assembler Lösung. Schneller kann's nicht gehen. 64Bit muß nicht sein. Aber Danke Dir, Sakura, aber da muß ich erstmal schauen, ob ich die Indy für D5 überhaupt noch bekomme. :) ![]() ![]()
Code:
Oar .. wie ich solche Seiten Liebe ...
404 - File or directory not found.
The resource you are looking for might have been removed, had its name changed, or is temporarily unavailable. hier hab ich zwar auch noch nen passenden Thread gefunden, aber da sind leider auch nur alte Links. ![]() Ich denke, da wird es auch nur noch Indy 9 für so alte Delphi5 geben ... meine ich, hätt ich mal gelesen. aber wo ... als ZIP-Download? wo bekommt Ihr das Zeug nur immer her? |
AW: Base64/ Mime für Dateien
[QUOTE=Capstone;1381024]Du (EDIT: damals) selbst geschrieben hast:
Zitat:
Viel Erfolg ...:cat:... |
AW: Base64/ Mime für Dateien
|
AW: Base64/ Mime für Dateien
Ist an sich schnell geschrieben:
Delphi-Quellcode:
Ich würde übrigens TMemoryStreams nehmen. Viele kleine Zugriffe auf TFileStream sind abartig langsam.
procedure Base64EncodeStream(Input, Output: TStream);
const Base64: array[0..64] of Byte = ( 65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90, 97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122, 48,49,50,51,52,53,54,55,56,57,43,47,$3D); var count: Byte; temp: Cardinal; i, j: Integer; begin Count := 0; Temp := 0; for i := 0 to (Input.Size + 2) div 3 - 1 do begin Count := Input.Read(temp, 3); temp := temp and $ff00 + temp shl 16 + temp shr 16; // Endianness drehen for j := 0 to Count do begin temp := temp shl 6; Output.WriteBuffer(Base64[(temp shr 18) and $3f], 1); end; end; for j := Count to 2 do Output.WriteBuffer(Base64[64], 1); end; |
AW: Base64/ Mime für Dateien
Liste der Anhänge anzeigen (Anzahl: 2)
ich grüße Euch,
und ich Danke Euch für Eure Vorschläge. mhh, ich schäme mich ja fast, nochmal fragen zu müssen, weil ich immer noch nicht klarkomme. Ich probier nun schon den ganzen Abend mit verschiedenen Verzeichnissen, Orten , und Tricks, die INDYs installiert zu bekommen, bzw, wenigstens die Units nutzen zu können. Also: Indy 9 + 10 hab ich runtergeladen, aber erstmal nur die 9er-ZIP entpackt und die Full5.bat ausgeührt (wegen vermutl. besserer Kompatibilität) Da wurden anscheinend alle klaglos compiliert. (alle dcu's wurden in C:\INDY\D5 erstellt) Dann hab ich, wie in der ManualInstall.txt beschrieben »dclIndy50.bpl« als Komponente bzw. dann auch als Package zu installieren, welche demnach in C:\INDY\d5 sein sollte, aber sich nur in C:\INDY\Source\ befindet. :( Zitat:
![]() Dennoch erhalte ich folgende Fehlermeldung: "<IDname> ist kein gültiger Bezeichner. Zitat:
![]() Ich hab zwar dann unter Projektoptionen die Pfade zu den Units in das Feld für die Suchpfade eingetragen und zumindest nach implementation die beiden Units eingetragen (uses IdMessageCoder, IdMessageCoderMIME;) Da meckert er wenigstens auch nichts dran. Aber außer, daß ich die Klasse TIdMessageCoderMIME (statt des idCodec64.Encode()) eintippen kann, läßt sich außer .create nicht viel damit machen. Encode ist nicht zu finden. idCodec64 wird gar nicht angeboten, wenn ich die Kontextergänzung CTRL+Shift + Leer nehme. Also hatte ich versucht die Procedur TIdMessageCoderMIME zu verwenden. Auch nix. Da ist also kein Weiterkommen, oder? Mhh, jetzt ist das ja für Euch mit 90% Delphi 10 auch schwer, da irgendwas zu diagnostizieren, was da einer mit seinem alten Delphi5 macht. Zudem sitz ich ja noch so weit weg. (oder gibt es im Raum Essen irgendwo Delphi Leute?) ------ Dann habe ich allerdings auch heute Nachmittag schon probiert, ob ich die Lösung von Redeemer umsetzen könnte. Doch war ich daran auch gescheitert.
Delphi-Quellcode:
Dann hab ich das hier
procedure TForm1.Button5Click(Sender: TObject);
var fin, fon : TMemoryStream; FN : String; err: Boolean; begin FN := 'C:\Users\Documents\DELPHI\b64\neu.txt'; fin :=TMemoryStream.Create(FN,fmOpenRead); // hier wären die Argumente zu viel/unpassend fon :=TMemoryStream.Create(FN + '2',fmOpenWrite); err := Base64EncodeStream (fin, Fon); if Err then Caption := 'FEHLER'; fin.free; son.free; end;
Delphi-Quellcode:
versucht.
procedure TForm1.Button5Click(Sender: TObject);
var fin, fon : TMemoryStream; fiS, foS : TFileStream; FN : String; err: Boolean; begin FN := 'C:\Users\Documents\DELPHI\b64\neu.txt'; Fis := TFileStream.Create(FN,fmOpenRead); FOS := TFileStream.Create(FN + 2,fmOpenRead); // fin := Fis; //TMemoryStream.Create(FN,fmOpenRead); // FAIL // fin.assign(Fis); // FAIL fon := TMemoryStream.Create(FN + '2',fmOpenWrite); // FAIL err := Base64EncodeStream (fiS, FoS); if Err then Caption := 'FEHLER'; fin.free; son.free; end; Aber das geht ja auch nicht. Wie gesagt mit Streams kenn ich mich nicht so aus. :( Ich hab zwar ein kurzes Buch, das behandelt Streams aber nur so am Rande. Eher Klick, Klick, Edit = fertig ist das Programm. Wüßte auch nicht, wo man sowas - und dann noch auf dieses Problem spezialisiert, gut lernen/lesen könnte. Also was ich bräuchte wären Datei->b64-Datei und Datei->b64-String Funktionen. Was mach ich denn falsch? |
AW: Base64/ Mime für Dateien
Meine Methode (oder besser gesagt MemoryStreams) benutzt man so:
Delphi-Quellcode:
var
Input, Output: TMemoryStream; begin Input := TMemoryStream.Create; Output := TMemoryStream.Create; try Input.LoadFromFile('meinedatei.bin'); Base64EncodeStream(Input, Output); Output.SaveToFile('meinedatei.txt'); finally Input.Free; Output.Free; end; end; |
AW: Base64/ Mime für Dateien
Danke, funktioniert jetzt auch bei mir so - in der Tat.
aber wo kann ich sowas nachlesen? Genau so ein Wissen fehlt mir ja. EDIT: aber also mit folgendem Code braucht er für ne 17 MB Datei (ca. 20 Sekunden?). (19969 Tics) Ne 5000 Bytes-Datei geht schneller: 2044 Tics. 10000 Bytes Datei: 6973 Tics. (hab hier nen 4 Jahre alten 2x 2.54 DualCore Laptop, 8 GB RAM, 1 TB HDD) Aber das kommt mir irgendwie langsam vor, oder?.
Delphi-Quellcode:
Schrieb Sakura nicht was von wenigen Sekunden? (4S für 80 MB?)
procedure TForm1.Button6Click(Sender: TObject);
var Input, Output: TMemoryStream; FN: String ; gt, gt2: Longword; diff : integer; begin Input := TMemoryStream.Create; Output := TMemoryStream.Create; try FN := 'C:\Users\Documents\DELPHI\fC\neu.txt'; gt := gettickcount; Input.LoadFromFile(FN ); Base64EncodeStream(Input, Output); Output.SaveToFile(FN + 'UUX'); gt2 := gettickcount; diff:= gt2 - gt; // diff := diff * 1000; memo1.Text:= inttostr(diff); finally Input.Free; Output.Free; end; end; |
AW: Base64/ Mime für Dateien
Habe das bei mir mit 90 MB getestet, dauerte etwa zwei Sekunden. Aber das war 'ne SSD. Mach mal die Ticks nur um meine Methode. Die sollte deutlich unter einer Sekunde brauchen, gerade für nur 17 MB.
Man sollte beim Programmieren schon lesen, was da steht. Wenn man
Delphi-Quellcode:
eingibt, erscheint automatisch die Programmierhilfe von Delphi und sagt „<Keine Parameter erwartet>“. Also ruft man die Methode ohne Parameter auf (Klammer wieder weg oder – wer’s mag – Klammer sofort schließen). Da hätten schon längst deine Alarmglocken schrillen sollen. Wenn die Methode keine Parameter erwartet, sind zwei Parameter natürlich zu viel.
Input := TMemoryStream.Create(
Ich habe noch nie ein Buch zu Delphi gelesen. Es begann mit der Anleitung zur Programmierung eines Euro-DM-Umrechners in PC-World, wo Delphi 6 PE beilag. Rest über die Dokumentation. (Das übt zwar die Aneignung von Wissen aus der Dokumentation, aber die Code-Qualität und Umsetzung früherer Projekte ist allerdings dementsprechend schlecht, da man z.B. nicht immer weiß, welche weiteren (besseren) Möglichkeiten es noch gibt, um dasselbe Problem zu lösen.) |
AW: Base64/ Mime für Dateien
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Der Sprung in die Function sollte doch nicht so lange brauchen, oder? höchtens 3 CPU Takte. oder wo genau meinst Du? und an einer HDD (vs. SSD) sollte das doch auch nicht liegen. Die hat immerhin schon 1 TB und ist erst 4 Jahre alt. Wieviel Umdrehungen hat die? 5000/s? ist ja komisch. Also ich verwende nur meinen Code hier (repost:)
Delphi-Quellcode:
das ganze Projekt hab ich mal hier raufgeladen.
procedure TForm1.Button1Click(Sender: TObject);
var Input, Output: TMemoryStream; STRI, FN: string; gt, gt2: Longword; diff: integer; begin Input := TMemoryStream.Create; Output := TMemoryStream.Create; try FN := '.\neu.txt'; gt := gettickcount; Input.LoadFromFile(FN); Base64EncodeStream(Input, Output); Output.SaveToFile(FN + 'b64'); gt2 := gettickcount; diff := gt2 - gt; // diff := diff * 1000; memo1.Text := inttostr(diff); finally Input.Free; Output.Free; end; end; dazu auf Zippy eine ca. 1o MB Binary. ![]() |
AW: Base64/ Mime für Dateien
Ich meinte mit "meiner Methode" nicht die TMemoryStream-Methoden zum Laden und Speichern. Mich würde interessieren, ob deine CPU so langsam ist, das damalige Delphi so ineffizient oder woran es sonst liegt.
|
AW: Base64/ Mime für Dateien
Guten Morgen,
ja, war ja auch nicht als Kritik gemeint. (das würd ich mir gegenüber einem Delphi-Erfahrenen, zudem Helfenden nicht wagen.) Hatte nach dem Posten noch die gettickcount noch ditrekt vor und hinter Deine Funktion gesetzt und compiliert. Brachte aber bei ner 10 MB Datei nur etwa 1 Sekunde Unterschied. (ca. 7000 statt ~6000 Tics) Hab dann auch ne 100 MB Datei versucht - und mußte das Programm nach 7 Minuten killen. Der kam gar nicht voran - unter Vollast!. ***** Das Programm wurde nach anfänglichem Fehlerüberprüfen in der IDE (klappte sogar mit 2 MB zügig in der IDE) später stets separat, außerhalb der IDE gestartet. (also der Debugger kann's nicht verzögern). ***** Meine Exe hab ich ja mit hochgeladen. Falls Du das in ner Sandbox laufen lassen möchtest. (Viren/Trojaner/Schadecode frei sollte es sein - ist nur mit STRG+F9 compiliert worden) Ja, die Gedanken kamen mir natürlich auch, ob meine Delphi D5 so ineffizient wäre. (aber ansich kann ich mir das nicht vorstellen, daß die damals dem Compiler so schlecht programmiert haben. OK, langsamer als ein M$ Compiler ... könnte er sein ... aaber eigentlich gibt es ja da nicht viel komplizierte Funktionen zu übersetzen. Das müßte ja schon resourcensparsam zur Exe zusammengekleistert sein, oder doch?)[die hatten doch schon 30 Jahre Erfahrung mit Compilerbau] Ich hab ja nichts verändert, wie man im Projekt ja sehen kann. Nur eingebaut und die Zeitmessung hinzugefügt. OK, mein Laptop ist nun 4 Jahre alt. Hat nur 8 GB RAM und nur 2x 2,54 GHz und 2 lausige Grafikkarten (Intel intern und 2GB nvidia auf dem Board obendrauf). Die 1 TB Festplatte drin. Mit 5400 U/m. Kein wassergekühlter highend Zocker-PC also. Abgesehn von Delphi und Windows spiele ich ja auch nicht :) Für Wörd und Exzel reicht der ja allemal. Aber was sollte da so langsam sein? OK, ich könnte ja auch die Datei vorher in den Speicher laden. Doch daß es daran liegt glaub ich nicht. Naja, vielleicht steckt in den 20 MB/ 2M Executables von heute doch effizientere Übersetzung. Eigenartig. Magst Du mal ggf. Deine Exe hochladen? LG |
AW: Base64/ Mime für Dateien
Liste der Anhänge anzeigen (Anzahl: 1)
Glückwunsch. Dein Delphi ist einfach nur scheißen-langsam.
Angehängt ist ein Kompilat deines Projekts mit Delphi 2009. Ich habe nichts gemacht außer es geöffnet und F9 gedrückt, dadurch wurde das Programme einige hundert Mal schneller. Das Kompilat meines Projekts ist auch angehängt, auch wenn es nichts bringt. Wenn du willst, ersetze mal beide WriteBuffer durch Write. Die beiden sind eigentlich identisch, aber wer weiß. Ein mögliches Problem wäre das zu feine Reservieren von Speicher. Füge doch einfach mal vor der for-Schleife folgende Zeile ein:
Delphi-Quellcode:
Wenn das noch immer nicht schneller geht, müsste man per Pointer in den Stream schreiben. Melde dich, ich ändere die Methode.
Output.Size := ((Input.Size + 2) div 3) * 4;
|
AW: Base64/ Mime für Dateien
Die Methode von mir hatte zwei Fehler, was zu einem ungültigen Ergebnis führte. Hier die korrekte Version:
Delphi-Quellcode:
Hier übrigens der Dekoder:
procedure Base64EncodeStream(Input, Output: TStream);
const Base64: array[0..64] of Byte = ( 65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90, 97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122, 48,49,50,51,52,53,54,55,56,57,43,47,$3D); var count: Byte; temp: Cardinal; i, j: Integer; begin Temp := 0; Count := 3; Output.Size := (Input.Size + 2) div 3 * 4; for i := 0 to (Input.Size + 2) div 3 - 1 do begin Count := Input.Read(temp, 3); temp := temp and $ff00 + temp shl 16 + temp shr 16 and $ff; // Endianness drehen (vereinfacht weil nur 3 Byte verwendet) for j := 0 to Count do begin Output.Write(Base64[temp shr 18 and $3f], 1); temp := temp shl 6; end; end; for j := Count to 2 do Output.Write(Base64[64], 1); // Schreibe ein Gleichzeichen zum Auffüllen end;
Delphi-Quellcode:
procedure Base64DecodeStream(Input, Output: TStream);
const Base64: array[Byte] of ShortInt = ( -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, -1, 0, 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,-1,-1,-1,-1,-1, -1,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,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1); var count, b: Byte; temp: Cardinal; i: Integer; begin Temp := 0; Count := 0; Output.Size := Trunc(Input.Size / 4 * 3); // maximal möglichen Output reservieren for i := 0 to Input.Size - 1 do begin Input.Read(b, 1); if Base64[b] > -1 then begin temp := temp shl 6 or Byte(Base64[b]); inc(Count); if Count = 4 then begin temp := temp and $ff00 + temp shl 16 + temp shr 16; // Endianness drehen (vereinfacht weil nur 3 Byte verwendet) Output.Write(temp, 3); temp := 0; Count := 0; end; end; end; if Count > 1 then // Rest behandeln, der kein 3er-Block ist (ein Base64-Rest kann nicht 1 lang sein) begin temp := temp shl (6 * (4 - Count)); temp := temp and $ff00 + temp shl 16 + temp shr 16; Output.Write(temp, Count - 1); end; Output.Size := Output.Position; // Scheint entgegen der Dokumentation TMemoryStream.Memory nicht zu löschen end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:36 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