![]() |
FileSplitter: Probleme mit großen Dateien
Habe folgende Mail bezüglich großer Dateien und meines FileSplitters bekommen:
Zitat:
Delphi-Quellcode:
function SplitFile(Filename, DestFolder: string; SplitSize, CntParts: Int64): Integer;
function GetClusterSize(Drive: Char): Cardinal; var SectorPerCluster: Cardinal; BytesPerSector : Cardinal; NumberOfFreeClusters: Cardinal; TotalNumberOfClusters: Cardinal; begin GetDiskFreeSpace(PChar(Drive + ':\'), SectorPerCluster, BytesPerSector, NumberOfFreeClusters, TotalNumberOfClusters); Result := SectorPerCluster * BytesPerSector; end; var hFile : THandle; SizeOfFile : Int64; hPart : THandle; Loop : Cardinal; Partname : string; BlockSize : Cardinal; MemBuffer : array of Byte; minlen : Int64; BytesToRead, BytesRead, BytesWritten: Integer; OverallBytesRead : Int64; ProgressCurrent, ProgressOld: Int64; begin TickStart := GetTickCount; BlockSize := -(-GetClusterSize(FileName[1]) and -GetClusterSize(DestFolder[1]) and -1048576); SetLength(MemBuffer, BlockSize - 1); bRunning := 1; OverallBytesRead := 0; SizeOfFile := GetFileSize(PChar(Filename)); hFile := CreateFile(PChar(Filename), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN or FILE_FLAG_WRITE_THROUGH, 0); if hFile <> INVALID_HANDLE_VALUE then begin for Loop := 1 to CntParts do begin // Reset variables ProgressOld := 0; BytesToRead := SplitSize; // build filename of the parts Partname := DestFolder + '\' + ExtractFilename(Filename) + Format('.%3.3d', [Loop]); if FileExists(Partname) then DeleteFile(PChar(Partname)); hPart := CreateFile(PChar(Partname), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN or FILE_FLAG_WRITE_THROUGH, 0); if hPart <> INVALID_HANDLE_VALUE then begin repeat minlen := Min(length(MemBuffer), BytesToRead); BytesRead := FileRead(hFile, MemBuffer[0], minLen); if BytesRead > -1 then begin BytesWritten := FileWrite(hPart, MemBuffer[0], BytesRead); Dec(BytesToRead, length(MemBuffer)); // progress stuff //////////////////////////////////////////////////// OverallBytesRead := OverallBytesRead + BytesWritten; ProgressCurrent := (OverallBytesRead * 100) div SizeOfFile; if ProgressCurrent <> ProgressOld then begin ProgressOld := ProgressCurrent; end; SendMessage(hApp, FSM_PROGRESS, ProgressCurrent, Integer(PChar(Partname))); end else begin MessageBox(hApp, PChar(SysErrorMessage(GetLastError)), PChar(APPNAME), 0); Break; end; ////////////////////////////////////////////////////////////////////// until (BytesToRead <= 0) or (bRunning = 0); end; FileClose(hPart); if bRunning = 0 then Break; end; FileClose(hFile); end; SendMessage(hApp, FSM_FINISH, GetTickCount - TickStart, GetLastError()); result := GetLastError(); end;
Delphi-Quellcode:
function CalcCntParts(const Filename: string; Size: Int64): Cardinal;
var FileSize : Int64; // >4GB begin result := 0; if Size > 0 then begin FileSize := GetFileSize(PChar(Filename)); if (FileSize > 0) and (FileSize div Size < High(Integer)) then result := (FileSize - 1) div Integer(Size) + 1; end; end; function CalcFileSize(const Filename: string; CntParts: Cardinal): Int64; var FileSize : Int64; begin Result := 0; FileSize := GetFileSize(PChar(Filename)); if (FileSize > 0) and (CntParts <> 0) then begin Result := (FileSize div CntParts) + 1; end; end;
Delphi-Quellcode:
Ich weiß nicht, wo ich den Fehlergemacht haben soll.
////////////////////////////////////////////////////////////////////////////////
// Procedure : FileRead // Comment : Reads the given amount of bytes into a buffer function FileRead(Handle: Integer; var Buffer; Count: LongWord): Integer; begin if not ReadFile(THandle(Handle), Buffer, Count, LongWord(Result), nil) then Result := -1; end; //////////////////////////////////////////////////////////////////////////////// // Procedure : FileWrite // Comment : Writes the buffer into the file function FileWrite(Handle: Integer; const Buffer; Count: LongWord): Integer; begin if not WriteFile(THandle(Handle), Buffer, Count, LongWord(Result), nil) then Result := -1; end; |
Re: FileSplitter: Probleme mit großen Dateien
Moin Michael,
hast du mal eine dummy-Datei in der erwähnten Größe erstellt und deinen Filesplitter damit durch den debugger gejagt ? |
Re: FileSplitter: Probleme mit großen Dateien
Das ist das Problem. Ich habe keine Partition mehr übrig mit genügend Platz. ;)
|
Re: FileSplitter: Probleme mit großen Dateien
Ich verstehe nicht, weshalb der Parameter CntParts überhaupt übergeben wird.
Angenommen, ich möchte eine Datei mit 5 GB in 650 MB grosse Stücke unterteilen. Dann gehe ich doch so vor (Pseudocode):
Delphi-Quellcode:
Auf diese Art braucht man keine For-Schleife und entgeht den ganzen Problemen mit Int64 Werten.
Datei öffnen
while not eof do begin ErzeugeNeueZieldatei; readsize := 0 do LesePuffer; // 8 kB lesen SchreibeZieldatei; // bis zu 8 kB schreiben if readBytes <> Buffersize then break; readsize := readsize + readBytes; until readsize >= 650 MB; SchlieseZielDatei; end; Kleiner Nachteil meiner Lösung: die Grösse der Zieldatei muss ein Vielfaches der Puffergrösse sein. Mit etwas Zusatzaufwand kann man das aber auch lösen. |
Re: FileSplitter: Probleme mit großen Dateien
Zitat:
|
Re: FileSplitter: Probleme mit großen Dateien
Zitat:
Wir kennen die Dateigrösse und die Grösse der Teildateien. Bringt man jetzt noch die Anzahl der Teildateien ins Spiel, ist das wie eine überbestimmte Gleichung.
Delphi-Quellcode:
Bist du sicher, dass du die richtige Funktion verwendest ?
SizeOfFile := GetFileSize(PChar(Filename));
Unter Delphi 5 sieht der Prototyp aus Windows.pas so aus:
Delphi-Quellcode:
Bist du sicher, dass deine Funktion korrekt arbeitet (also wirklich int64 liefert) ?
function GetFileSize(hFile: THandle; lpFileSizeHigh: Pointer): DWORD; stdcall;
|
Re: FileSplitter: Probleme mit großen Dateien
Sieht bei mir so aus:
Delphi-Quellcode:
Das mit der for-Schleife wäre zu überlegen. Wenn Teile angegeben werden, müsste man eben erst die Größe der Teilstücke ausrechnen. Ich werde mir das ml überlegen.
function GetFileSize(Filename: String): Int64;
var fFile : THandle; wfd : TWIN32FINDDATA; begin result := -1; if not FileExists(Filename) then exit; fFile := FindFirstfile(pchar(Filename), wfd); if fFile = INVALID_HANDLE_VALUE then exit; result := (wfd.nFileSizeHigh * (Int64(MAXDWORD) + 1)) + wfd.nFileSizeLow; windows.FindClose(fFile); end; |
Re: FileSplitter: Probleme mit großen Dateien
Zitat:
Das mit dem Multiplizieren ((wfd.nFileSizeHigh * (Int64(MAXDWORD) + 1)) löst bei mir "schlechte Gefühle" aus. Ich glaube die VCL bzw. der Compiler kann gar keine Multiplikationen der Bauart 64bit * 32Bit = 64bit ausführen.
Delphi-Quellcode:
function FileGetSize(const FileName: string): Int64; // kopiert aus der JCL
var SearchRec: TSearchRec; OldMode: Cardinal; Size: TULargeInteger; begin Result := -1; OldMode := SetErrorMode(SEM_FAILCRITICALERRORS); try if FindFirst(FileName, faAnyFile, SearchRec) = 0 then begin Size.LowPart := SearchRec.FindData.nFileSizeLow; Size.HighPart := SearchRec.FindData.nFileSizeHigh; Result := Size.QuadPart; SysUtils.FindClose(SearchRec); end; finally SetErrorMode(OldMode); end; end; |
Re: FileSplitter: Probleme mit großen Dateien
Hallo Andreas,
Zitat:
Freundliche Grüße |
Re: FileSplitter: Probleme mit großen Dateien
Liste der Anhänge anzeigen (Anzahl: 1)
So, ich habe mal die vorgeschlagenen Änderungen gemacht. Anbei die aktuelle Exe.
Hätte jemand von euch genug Festplattenkapazität, um das bitte mal mit Dateien größer 6,6 GB und Teilstücken größer 2048 MB zu testen, eben wie inder Fehlermeldung im ersten Posting? Wäre sehr nett. Allerdings glaube ich nicht, dass die Änderungen etwas mit dem Fehler zu tun haben. Mir fällt gerade ein, kann es sein das er versucht hat die Teilstücke auf einer FAT32 Partition zu erstellen? Die kann doch nur Dateien bis 2GB verwalten oder? |
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:12 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 by Thomas Breitkreuz