Einzelnen Beitrag anzeigen

Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#1

FileSplitter: Probleme mit großen Dateien

  Alt 25. Mär 2008, 13:52
Habe folgende Mail bezüglich großer Dateien und meines FileSplitters bekommen:
Zitat:
FileSplitter 5.7.0.3 (andere Versionen habe ich nicht getestet) versagt,
wenn die gesplitteten Dateien größer als 2047 MB sein sollen (getestet
unter XP SP2 mit NTFS). Ich wollte eine 6664,95 MB große Datei splitten
und erhielt dabei folgende Effekte:

Bei Angabe der Dateigröße zwischen 2048 und 4095 MB erscheint eine
10-stellige Anzahl Teile, und beim Versuch der Ausführung beendet sich
das Programm mit einem Runtime error.

Bei Angabe von 4096 MB als Dateigröße erhält man 0 Dateien und eine
Ausführung ist nicht möglich.

Bei Angabe von 4097 MB und mehr subtrahiert das Programm 4096 MB von der
Eingabe. Bei 4097 MB erhalte ich in meinem Beispiel also 6665 Teile zu 1 MB.

Bei Angabe von 2 bzw. 3 bei der Anzahl Dateien wird die korrekte
Dateigröße angezeigt und das Programm auch ausgeführt. Man erhält dann
allerdings 2 bzw 3 Dateien zu je 1 MB (und die Batch-Datei zum
Zusammenfügen).
Das wundert mich etwas, da ich eigentlich überall mit Int64 arbeite, wenn es um die Dateigrößen etc. geht. Hier mal die relevanten Codeauschnitte:

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:
////////////////////////////////////////////////////////////////////////////////
// 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;
Ich weiß nicht, wo ich den Fehlergemacht haben soll.
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat