Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Datei kürzen (truncate) für files > 4.294 GB (https://www.delphipraxis.net/56954-datei-kuerzen-truncate-fuer-files-4-294-gb.html)

Jasmine 14. Nov 2005 08:49


Datei kürzen (truncate) für files > 4.294 GB
 
Hallo Liebe Delphi Freunde,

ich möchte gerne eine Datei kürzen, ohne diese natürlich zu kopieren.

Die truncate Procedure ist dafür sehr gut geeignet, jedoch habe ich festgestellt,
dass diese nur bis 4.294 GB, also 32 bit, 2^32 geht, wenn ich mit der Seek Procedure
auf die record position fahre und dann truncate anwende.

Ich kann bei Seek keinen int64 übergeben.

Kennt jemand eine andere Lösung, wie ich dieses Problemchen lösen kann.

Danke im Voraus für eure Hilfe.

Jasmine
:cat:

Muetze1 14. Nov 2005 08:52

Re: Datei kürzen (truncate) für files > 4.294 GB
 
Seek kann doch auch von der aktuellen Position aus seeken (SO_FROMCURRENT). Somit seeke bis zum Ende der 2^32 Grenze und dann von der aktuellen Stelle weiter ...

shmia 14. Nov 2005 16:29

Re: Datei kürzen (truncate) für files > 4.294 GB
 
Du musst halt über Windows API gehen. Leider ist SetFilePointerEx nicht in der Unit windows deklariert.
Delphi-Quellcode:
function SetFilePointerEx(hFile: HANDLE; liDistanceToMove: LARGE_INTEGER;
  lpNewFilePointer: PLARGE_INTEGER; dwMoveMethod: DWORD): BOOL; stdcall;

function SetFilePointerEx; external kernel32 name 'SetFilePointerEx';
Danach muss man die Datei auf die neue Länge setzen:
Delphi-Quellcode:
SetEndOfFile(filestream.Handle);

himitsu 14. Nov 2005 16:41

Re: Datei kürzen (truncate) für files > 4.294 GB
 
Und zwar sind die Dateifunktionen/-prozeduren intern nur auf 32 Bit ausgelegt, aber glücklicher Weise funktioniert der größte Teil dennoch oberhalb dieser Grenze.

Der Grund ist, daß nur ein 32-Bit-Zeiger verwendet wird und daher an die API-Funktionen eben nur maximal 32-Bit übergeben werden können.

Abhilfe hab ich vor kurzem mal geschaffen :mrgreen:
Es brauchen also nur die entsprechenden Funtionen/Prozeduren ersetzt zu werden, der Rest bleibt gleich.

64-Bit für TextFile / File of xxx (die Datei aus Beitrag #2 verwenden)


Die andere Lösung wurde ebenfalls schon vorgeschalgen ... einfach direkt an die Win-API wenden :roll:


@shmia: dman kann auch das normale SetFilePointer verwenden und dieses ist in der Unit Windows vorhanden ... siehe meine Unit :zwinker:
(die Delphi-Funktionen haben wie gesagt nur den 32-Bit-Integer und daher werden die höheren Bits einfach nicht übergeben ... bei SetFilePointer ist die Position ganz einfach auf zwei 32-Bit-Werte aufgesplittet, wobei der höherwertige Anteil als Pointer übergeben wird und daher auch weggelassen werden kann, was halt einfach mal gemacht wurde ^^)

Jasmine 17. Nov 2005 15:46

Re: Datei kürzen (truncate) für files > 4.294 GB
 
Hallo zusammen,

vielen Dank für eure Tips.

Ich habe die Lösung von himitsu mit der Seek64 funktion ausprobiert,
die jedoch bei mir, beim Aufruf von
TFlushFunc(TFileRec(F).FlushFunc)(F);
eine Exception der Klasse EAccessViolation, Zugriffsverletzung an Adresse 00000000,
Lesen von Adresse 00000000, verursacht.

Habe dann den Aufruf ausgeklammert und alles klappt einwandfrei.

Ebenso :
recNum := recNum * TFileRec(F).RecSize;

da ich irgendwie nicht verstehe, warum mein neuer Pointer Wert mit der Größe der
eigendlichen Datei mulipliziert werden sollte ?!?

Über lehrreiche Erklärungen würde ich mich freuen.

Danke nochmals an alle,

Jasmine

:kiss:

himitsu 17. Nov 2005 17:24

Re: Datei kürzen (truncate) für files > 4.294 GB
 
OK, der Fehler ist mir zwar noch unbekannt, aber ich werd' mir das nochmal genauer ansehen, allerdings denke ich im Moment noch nicht, daß es an meinen Funktionen liegt.

Kannst du eventuell mal etwas Code aus deinem Programm zur verfügung stellen (notfalls auch per PN), damit ich mir dieses auch nochmal direkt an deinem Beispiel ansehen zu können?

TFlushFunc(TFileRec(F).FlushFunc)(F);
Schau mal bitte nach, auf was der Pointer TFileRec(F).FlushFunc zeigt.
Dieses "Zugriffsverletzung an Adresse 00000000" verleitet mich irgendwie zu der Annahme, daß dieser eventuell auf NIL steht.
War schon drauf und drann eine Prüfung einzubauen, aber dann fiehl mir wieder ein, daß dieses eigentlich niemals auf nil stehen sollte, selbst wenn keine Flush-Funktion vorhanden ist, sollte zumindestens eine Dummy-Funktion darin zu finden sein.

PS: Hast du auch die Unit aus Beitrag #2 verwendet?
Die in #1 hatte leider noch ein/zwei kleine Fehlerchen drin. :wall:



Zitat:

recNum := recNum * TFileRec(F).RecSize;
Dieses resultiert daraus, daß bei typisierten Dateien die Position nicht in Byte, sondern Records angebeben wird.
Also bei einer Recordgröße von z.B. 16 Byte wird z.B. nicht Position = 160 (Byte), sonder Position = 10 an-/ausgegeben.

Jasmine 17. Nov 2005 17:39

Re: Datei kürzen (truncate) für files > 4.294 GB
 
Hallo himitsu,

also im Prinzip habe mir Dein Beispiel angeschaut (64bit für ..),
und mir aus File64.pas nur die Seek64 Funktion geholt.

Unter Interfaces habe ich :

Procedure Seek64 (Var F{: File of xxx}; recNum: Int64);

Unter Implementation habe ich :

Type TLargeIntRec = packed Record Case Byte of
0: (Org: Int64);
5: (Lo: LongWord; Hi: LongInt);
End;
TFlushFunc = Function(Var F): Integer;

und Deine Prozedur :

Procedure Seek64(Var F; recNum: Int64);
Begin
If (TFileRec(F).Mode >= fmInput) and (TFileRec(F).Mode <= fmInOut) Then Begin
TFlushFunc(TFileRec(F).FlushFunc)(F);
TTextRec(F).BufEnd := 0;
TTextRec(F).BufPos := 0;
recNum := recNum * TFileRec(F).RecSize;
If (SetFilePointer(TFileRec(F).Handle, TLargeIntRec(recNum).Lo, @TLargeIntRec(recNum).Hi, FILE_BEGIN)
= Cardinal(-1)) and (TLargeIntRec(recNum).Hi = 0) Then SetInOutRes(GetLastError);
End Else SetInOutRes(103);
End;

in meinen Code integriert.
Das wars eigendlich.

Der Aufrug erfolgt :

AssignFile(f,DNAFilenameLoad);
//FileMode:=2;
//Reset(f,1);
Reset(f);
Seek64(f,NewEndPosition); // int64
truncate(f);
CloseFile(f);

Jedoch so klappte es nicht un es ergab die Exception, also habe ich
in Deiner Prozedur, wie gesagt, einiges ausgeklammert.
Erkläre mir doch mal bitte den Sinn von:

recNum := recNum * TFileRec(F).RecSize;

Danke.



Viele Grüße,
Jasmine

himitsu 17. Nov 2005 17:47

Re: Datei kürzen (truncate) für files > 4.294 GB
 
zu "recNum := recNum * TFileRec(F).RecSize;" hab ich oben noch was nachgetragen ^^
Und dieses muß auch (unbedingt) enthalten sein, denn es ist im Original auch drin und meine Funktionen sollen/müssen ja kompatibel zu diesem sein. ;)

Wie ist denn deine Dateivariable (f) definiert?


PS: mach mal bitte das Delphi-Tag um deine Quellcodes ... so läßt es sich ein bissl schwer lesen.

himitsu 18. Nov 2005 01:11

Re: Datei kürzen (truncate) für files > 4.294 GB
 
OK, das Problem bei TFlushFunc(TFileRec(F).FlushFunc)(F); hab ich beseitigt.

Füge bitte noch die folgende Prüfung mit ein:
Code:
[color=red]If TFileRec(F).FlushFunc <> nil Then[/color] TFlushFunc(TFileRec(F).FlushFunc)(F);
Bei Textdateien ist es so, das selbst wenn keine Flush-Funktionalität vorhanden ist, daß dann wenigstens eine Dummy-Funktion (FileNOPProc) angegeben ist, wobei bei den typisierten Dateien nichts angegeben ist, weßhalb dieses durch die Initialisierung auf 0 steht.

Da meine Seek64 inoffiziell sogar für Textdateien verwendet werden kann, welches bei Seek eigentlich nicht möglich ist, mußte halt der Puffer darin mit behandelt werden, im Gegensatz zum Original.

Jasmine 22. Nov 2005 10:56

Re: Datei kürzen (truncate) für files > 4.294 GB
 
Hallo himitsu,

Delphi-Quellcode:
f: File of Byte;
Klappt nun alles.

Vielen Dank für die Erklärungen.

Jasmine

:cat:


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:14 Uhr.
Seite 1 von 2  1 2      

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