FAQ » Pliki

Jak skopiować plik do końca

Jak skopiować plik do końca?
Potrzeba nam do tego plik ,który nie skopiował się do końca :).

Delphi 7
Żeby to było w miarę możliwe i wygodne napisałem klasę pochodną od TFileStream ,która uzupełnia ją o jedną funkcję - CopyRest.

{-=================-}
{|  [email protected]  |}
{-=================-}
unit CopyRest;
 
interface
 
uses
  Classes;
 
type
  TCRFileStream = class(TFileStream)
  public
    function CopyRest(Source: TStream): Int64;
  end;
 
implementation
 
function TCRFileStream.CopyRest(Source: TStream): Int64;  //funkcja zwraca wartość przedstawiającą ilość zapisanych bajtów
const
  MaxBufSize = $F000; // Maksymalny rozmiar buforu. Dla przejżystości napiszę ,że w systemie dziesiętnym jest równy 61440
var
  BufSize, N: Integer;
  Buffer: PChar;
  Pos: Int64;
begin
  Pos := source.Size - Size;
  Source.Seek(Pos*-1,soFromEnd);
  Seek(0,soFromEnd);
  Result := Pos;
  if Pos > MaxBufSize then BufSize := MaxBufSize else BufSize := Pos;
  GetMem(Buffer, BufSize);
  try
    while Pos <> 0 do
    begin
      if Pos > BufSize then N := BufSize else N := Pos; 
      Source.ReadBuffer(Buffer^, N);
      WriteBuffer(Buffer^, N);
      Dec(Pos,N);
    end;
  finally
    FreeMem(Buffer, BufSize);
  end;
end;
 
end.


A teraz mały przykład:

procedure TForm1.Button1Click(Sender: TObject);
var
  Read, Write : TCRFileStream;
  plik1, plik2 : TFileName;
begin
  plik1 := 'C:\1.txt';        //zkąd
  plik2 := 'C:\folder\1.txt'; //dokąd
  try
    Read := TCRFileStream.Create(plik1,fmOpenRead or fmShareDenyNone);
    if FileExists(plik2) then // jeszcze lepiej by było sprawdzić po bitach w pliku, ale to już pozostawiam wam!
    begin
      try
        Write := TCRFileStream.Create(plik2,fmOpenWrite);
        Write.CopyRest(Read);
      finally
        Write.Free;
      end;
    end
    else
    begin
      try
        Write := TCRFileStream.Create(plik2,fmCreate);
        Write.CopyFrom(Read,0);
      finally
        Write.Free;
      end;
    end;
  finally
    Read.Free;
  end;
end;

Oczywiście ten przykład w pełni nie wykorzystuje wszystkich możliwości :).

Aby przykład działał poprawnie ,plik CopyRest.pas należy umieścić w katalogu z kodem programu oraz w deklaracjach uses dodać CopyRest.

Delphi 8 .NET
W Delphi 8 .NET niepotrzebne jest stworzenie jakiejkolwiek klasy.
unit WinForm1;
 
interface
 
uses
  System.Drawing, System.Collections, System.ComponentModel,
  System.Windows.Forms, System.Data, System.Configuration, System.Resources, System.IO, System.Threading;
 
type
  TWinForm1 = class(System.Windows.Forms.Form)
  {$REGION 'Designer Managed Code'}
  strict private
    {....}
  {$ENDREGION}
  strict protected
    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    procedure Dispose(Disposing: Boolean); override;
  private
    { Private Declarations }
  public
    CopyFrom, CopyTo : string;
    t : Thread;
    constructor Create;
    procedure Kopiuj;
  end;
 
  [assembly: RuntimeRequiredAttribute(TypeOf(TWinForm1))]
 
implementation
{...}
 
procedure TWinForm1.Kopiuj;
var
  i : integer;
  FsFrom, FsTo : FileStream;
  BrFrom : BinaryReader;
  BrTo : BinaryWriter;
  BufferL : Integer;
begin
  Button2.Enabled := false;
  BufferL := 6144;
  FsFrom := FileStream.Create(CopyFrom, FileMode.Open, FileAccess.Read, FileShare.Read);
  FsTo := FileStream.Create(CopyTo,FileMode.Append);
  FsFrom.Position := FsTo.Length;
  ProgressBar1.Maximum := FsFrom.Length;
  ProgressBar1.Value := FsTo.Length;
  BrFrom := BinaryReader.Create(FsFrom);
  BrTo := BinaryWriter.Create(FsTo);
  while FsFrom.Length <> FsTo.Position do
  begin
    if (FsFrom.Length - FsFrom.Position) < BufferL then
      BufferL := FsFrom.Length - FsFrom.Position;
    BrTo.Write(BrFrom.ReadBytes(BufferL));
    ProgressBar1.Value := ProgressBar1.Value + BufferL;
  end;
  Button2.Enabled := true;
end;
 
procedure TWinForm1.TWinForm1_Closed(sender: System.Object; e: System.EventArgs);
begin
  if t <> nil then
    t.Abort;
end;
 
procedure TWinForm1.Button2_Click(sender: System.Object; e: System.EventArgs);
begin
  if (OpenFileDialog1.ShowDialog = System.Windows.Forms.DialogResult.OK) then
    CopyFrom := OpenFileDialog1.FileName;
  if (SaveFileDialog1.ShowDialog = System.Windows.Forms.DialogResult.OK) then
    CopyTo := SaveFileDialog1.FileName;
  t := Thread.Create(Kopiuj);
  t.Start;
end;


Pozdrawiam!

6 komentarzy

qs 2006-08-14 19:10

;) fajnie jakby to jeszcze działało tak jak to opisuje autor ;) :)

warlock 2004-11-17 14:43

To może ocena co!?
Program z wykorzystaniem tego kodu i z kodem źródłowym znajduje się na:
http://members.lycos.co.uk/totalclone/

brodny 2004-08-05 17:51

To w takim razie przyda się, nawet bardzo :)

brodny 2004-08-01 18:40

Z tym "do końca" chodzi Ci o to, że np. plik nie został skopiowany z powodu błędów odczytu z miejsca źródłowego etc. czy masz może inne pojęcie "końców"? :) Wiem, że jestem CKM :)

warlock 2004-08-02 16:36

Tak jak piszesz! Przerwane kopiowanie - reset kompa itp.