unit U_ExtFileCopy; {$mode objfpc}{$H+} { Composant TExtFileCopy Développé par: Matthieu GIROUX Composant non visuel permettant de copier un fichier plus rapidement que par le fonction copy de windows. Compatible Linux Attention: La gestion de la RAM étant calamiteuse sous Win9x, l' utilisation de ce composant provoque une grosse une forte baisse de la mémoire disponible. Sous WinNT/2000 il n' y a pas de problèmes Version actuelle: 1.0 Mises à jour: } interface uses SysUtils, Classes,ComCtrls, StrUtils, lresources ; var GS_COPYFILES_ERROR_DIRECTORY_CREATE : String = 'Erreur à la création du répertoire' ; GS_COPYFILES_ERROR_IS_FILE : String = 'Ne peut copier dans le fichier' ; GS_COPYFILES_ERROR_CANT_COPY : String = 'Impossible de copier ' ; GS_COPYFILES_ERROR_PARTIAL_COPY : String = 'Copie partielle du fichier ' ; GS_COPYFILES_ERROR_PARTIAL_COPY_SEEK: String = 'Erreur à la copie partielle du fichier ' ; GS_COPYFILES_ERROR_CANT_READ : String = 'Impossible de lire le fichier ' ; GS_COPYFILES_ERROR_CANT_CHANGE_DATE : String = 'Impossible d''affecter la date au fichier ' ; GS_COPYFILES_ERROR_CANT_CREATE : String = 'Impossible de créer le fichier ' ; GS_COPYFILES_ERROR_CANT_APPEND : String = 'Impossible d''ajouter au fichier ' ; GS_COPYFILES_ERROR_FILE_DELETE : String = 'Impossible d''effacer le fichier ' ; GS_COPYFILES_CONFIRM_FILE_DELETE : String = 'Voulez-vous effacer le fichier ' ; GS_COPYFILES_CONFIRM : String = 'Demande de confirmation' ; type TECopyOption = ( cpCopyAll, cpUseFilter, cpNoStructure, cpCreateBackup, cpCreateDestination, cpDestinationIsFile ); TECopyOptions = set of TECopyOption; TECopyEvent = procedure(Sender : Tobject; const BytesCopied,BytesTotal : cardinal) of object; TEReturnEvent = procedure(Sender : Tobject; var Continue : Boolean ) of object; TECopyErrorEvent = procedure(Sender : Tobject; const ErrorCode : Integer ; var ErrorMessage : AnsiString ; var ContinueCopy : Boolean ) of object; TECopyFinishEvent = procedure(Sender : Tobject; const ASource, ADestination : AnsiString ; const Errors : Integer ) of object; TEChangeDirectoryEvent = procedure(Sender : Tobject; const NewDirectory, DestinationDirectory : AnsiString ) of object; const lco_Default = [cpCopyAll,cpUseFilter]; CST_COPYFILES_ERROR_IS_READONLY = faReadOnly ; CST_COPYFILES_ERROR_UNKNOWN = -1 ; CST_COPYFILES_ERROR_IS_DIRECTORY = faDirectory ; CST_COPYFILES_ERROR_IS_FILE = 1 ; CST_COPYFILES_ERROR_DIRECTORY_CREATE = 2 ; CST_COPYFILES_ERROR_CANT_COPY = 3 ; CST_COPYFILES_ERROR_CANT_READ = 4 ; CST_COPYFILES_ERROR_CANT_CREATE = 5 ; CST_COPYFILES_ERROR_CANT_APPEND = 6 ; CST_COPYFILES_ERROR_FILE_DELETE = 7 ; CST_COPYFILES_ERROR_PARTIAL_COPY = 8 ; CST_COPYFILES_ERROR_PARTIAL_COPY_SEEK = 9 ; CST_COPYFILES_ERROR_CANT_CHANGE_DATE = 10 ; type { TExtFileCopy } TExtFileCopy = class(TComponent) private FOnChange : TEChangeDirectoryEvent ; FSizeTotal : Int64 ; FErrors , FSizeProgress : Integer ; FOnSuccess : TECopyFinishEvent; FOnFailure : TECopyErrorEvent ; FBeforeCopy : TEReturnEvent ; FBeforeCopyBuffer , FOnProgress : TECopyEvent; FBufferSize : integer; FOptions : TECopyOptions ; FFilter, FSource,FDestination : string; FInProgress : Boolean; procedure SetBufferSize (Value : integer); procedure SetDestination(Value : String); procedure SetSource(Value: String); protected FBuffer : array[0..65535] of char; function BeforeCopyBuffer ( var li_SizeRead, li_BytesTotal : Longint ) : Boolean ; virtual ; function BeforeCopy : Boolean ; virtual ; procedure AfterCopyBuffer ; virtual ; { Déclarations protégées } public function EventualFailure ( const ai_Error : Integer ; as_Message : AnsiString ):Boolean; virtual ; function InternalDefaultCopyFile ( const as_Source, as_Destination : String ):Boolean; virtual ; procedure InternalFinish ( const as_Source, as_Destination : String ); virtual ; constructor Create(AOwner : Tcomponent);override; property InProgress : Boolean read FInprogress; Function CopyFile ( const as_Source, as_Destination : String ; const ab_AppendFile, ab_CreateBackup : Boolean ):Integer; Procedure CopySourceToDestination; published property BufferSize : integer read FBufferSize write SetBufferSize default 65536; property Source : string read FSource write SetSource; property Mask : string read FFilter write FFilter; property Destination : string read FDestination write SetDestination; property Options : TECopyOptions read FOptions write FOptions default lco_Default ; property OnSuccess : TECopyFinishEvent read FOnSuccess write FOnSuccess; property OnFailure : TECopyErrorEvent read FOnFailure write FOnFailure; property OnProgress : TECopyEvent read FOnProgress write Fonprogress; property OnBeforeCopyBuffer : TECopyEvent read FBeforeCopyBuffer write FBeforeCopyBuffer; property OnBeforeCopy : TEReturnEvent read FBeforeCopy write FBeforeCopy; property OnChange : TEChangeDirectoryEvent read FOnChange write FOnChange; end; {TExtFilePartialCopy} TExtFilePartialCopy = class(TExtFileCopy) private lb_ExcludedFound : Boolean ; lpch_excludeStart, lpch_excludeEnd : String ; FExcludeStart , FExcludeEnd : String ; FExcludeReading : Boolean; protected function BeforeCopyBuffer ( var li_SizeRead, li_BytesTotal : Longint ) : Boolean ; override ; function BeforeCopy : Boolean ; override ; procedure AfterCopyBuffer ; override ; { Déclarations protégées } public constructor Create(AOwner : Tcomponent);override; published property ExcludeReading : Boolean read FExcludeReading write FExcludeReading default False ; property ExcludeStart : String read FExcludeStart write FExcludeStart ; property ExcludeEnd : String read FExcludeEnd write FExcludeEnd ; end; procedure Register; implementation uses functions_file, Forms, Dialogs, Controls ; {TExtFileCopy} constructor TExtFileCopy.Create(AOwner :Tcomponent); begin inherited Create(AOwner); Options := lco_Default ; FBufferSize := 65536; FInProgress := False; end; procedure TExtFileCopy.SetBufferSize(Value : integer); begin If not FInprogress then begin If Value > high ( FBuffer ) then Value := high ( FBuffer ) + 1 Else FBufferSize := Value; end; end; procedure TExtFileCopy.SetDestination(Value: String); begin if FDestination <> Value Then Begin FDestination := Value; End; end; procedure TExtFileCopy.SetSource(Value: String); begin if FSource <> Value Then Begin FSource := Value; if not ( csDesigning in ComponentState ) and Assigned ( @FOnChange ) Then FOnChange ( Self, FSource, FDestination ); End; end; function TExtFileCopy.BeforeCopyBuffer(var li_SizeRead, li_BytesTotal : Longint ): Boolean; begin Result := True ; if Assigned ( FBeforeCopyBuffer ) Then FBeforeCopyBuffer ( Self, li_SizeRead, li_BytesTotal ); end; function TExtFileCopy.BeforeCopy: Boolean; begin Result := True ; if Assigned ( FBeforeCopy ) Then FBeforeCopy ( Self, Result ); end; procedure TExtFileCopy.AfterCopyBuffer; begin end; Function TExtFileCopy.CopyFile ( const as_Source, as_Destination : String ; const ab_AppendFile, ab_CreateBackup : Boolean ):Integer; var li_SizeRead,li_SizeWrite,li_TotalW, li_RealTotal : Longint; li_SizeTotal : Int64 ; li_HandleSource,li_HandleDest, li_pos, li_Confirm : integer; ls_FileName, ls_FileExt,ls_Destination : String ; lb_FoundFile : Boolean; lsr_data : Tsearchrec; begin Result := 0 ; li_Confirm := mrYes ; FindFirst(as_Source,faanyfile,lsr_data); li_RealTotal := lsr_data.size ; li_SizeTotal := lsr_data.Size; inc ( FSizeTotal, li_SizeTotal ); li_TotalW := 0; findclose(lsr_data); try li_HandleSource := fileopen(as_Source,fmopenread); Except On E: Exception do Begin Result := CST_COPYFILES_ERROR_CANT_READ ; EventualFailure ( Result, GS_COPYFILES_ERROR_CANT_READ + as_Destination ); Exit ; End ; End ; ls_Destination := as_Destination ; if ab_AppendFile and fileexists(as_Destination) then try FindFirst(as_Destination,faanyfile,lsr_data); li_HandleDest := FileOpen(as_Destination, fmopenwrite ); FileSeek ( li_HandleDest, lsr_data.Size, 0 ); findclose(lsr_data); Except Result := CST_COPYFILES_ERROR_CANT_APPEND ; EventualFailure ( Result, GS_COPYFILES_ERROR_CANT_APPEND + as_Destination ); Exit ; End Else Begin If fileexists(ls_Destination) then Begin FindFirst(as_Destination,faanyfile,lsr_data); if ( ab_CreateBackup ) Then try ls_FileName := lsr_data.Name; ls_FileExt := '' ; li_pos := 1; while ( PosEx ( '.', ls_FileName, li_pos + 1 ) > 0 ) Do li_pos := PosEx ( '.', ls_FileName, li_pos + 1 ); if ( li_Pos > 1 ) Then Begin ls_FileExt := Copy ( ls_FileName, li_pos, length ( ls_FileName ) - li_pos + 1 ); ls_FileName := Copy ( ls_FileName, 1, li_pos - 1 ); End ; li_pos := 0 ; while FileExists ( ls_Destination ) do Begin inc ( li_pos ); ls_Destination := ExtractFilePath ( as_Destination ) + DirectorySeparator + ls_FileName + '-' + IntToStr ( li_pos ) + ls_FileExt ; End Except Result := -1 ; EventualFailure ( Result, as_Destination ); Exit ; End Else try if li_Confirm <> mrAll Then li_Confirm := MessageDlg ( GS_COPYFILES_CONFIRM, GS_COPYFILES_CONFIRM_FILE_DELETE, mtConfirmation, [mbYes,mbNo,mbAll,mbCancel], 0 ); if li_Confirm = mrCancel Then Abort ; if li_Confirm = mrNo Then Exit ; Deletefile(as_Destination); Except Result := CST_COPYFILES_ERROR_FILE_DELETE ; EventualFailure ( Result, GS_COPYFILES_ERROR_FILE_DELETE + as_Destination ); Exit ; End ; findclose(lsr_data); End ; try li_HandleDest := filecreate(ls_Destination); Except Result := CST_COPYFILES_ERROR_CANT_CREATE ; EventualFailure ( Result, GS_COPYFILES_ERROR_CANT_CREATE + as_Destination ); Exit ; End end ; if not BeforeCopy Then Exit ; lb_FoundFile := False; while not lb_FoundFile do try li_SizeRead := FileRead(li_HandleSource,FBuffer,FbufferSize); if ( li_SizeRead <= 0 ) and ( li_TotalW < li_RealTotal ) Then try FileSeek ( li_HandleSource, 64, li_TotalW ); Inc ( li_TotalW, 64 ); Continue ; Except Result := CST_COPYFILES_ERROR_PARTIAL_COPY_SEEK ; EventualFailure ( Result, GS_COPYFILES_ERROR_PARTIAL_COPY_SEEK + as_Destination ); End ; if BeforeCopyBuffer ( li_SizeRead, li_TotalW ) Then Begin li_SizeWrite := Filewrite(li_HandleDest,Fbuffer,li_SizeRead); Application.ProcessMessages; inc( li_TotalW, li_SizeWrite ); if ( li_SizeRead < FBufferSize ) and ( li_TotalW >= li_RealTotal ) then lb_FoundFile := True; if li_SizeWrite < li_SizeRead then Begin Result := CST_COPYFILES_ERROR_PARTIAL_COPY ; EventualFailure ( Result, GS_COPYFILES_ERROR_PARTIAL_COPY + as_Destination ); End ; if assigned(FonProgress) then FonProgress(self, FSizeProgress + li_TotalW,FSizeTotal); End ; AfterCopyBuffer ; Except Result := CST_COPYFILES_ERROR_CANT_COPY ; EventualFailure ( Result, GS_COPYFILES_ERROR_CANT_COPY + '( ' + as_Source + ' -> ' + as_Destination + ' )' ); Exit ; End ; try filesetdate(li_HandleDest,filegetdate(li_HandleSource)); Except Result := CST_COPYFILES_ERROR_CANT_CHANGE_DATE ; EventualFailure ( Result, GS_COPYFILES_ERROR_CANT_CHANGE_DATE + as_Destination ); Exit ; End ; fileclose(li_HandleSource); fileclose(li_HandleDest); if Result = 0 then Begin inc ( FSizeProgress, li_TotalW ); InternalFinish ( as_Source, as_Destination ); Result := 0 ; End ; Application.ProcessMessages ; end; function TExtFileCopy.InternalDefaultCopyFile ( const as_Source, as_Destination : String ):Boolean; var li_Error : Integer ; begin Result := True ; li_Error := CopyFile ( as_Source, as_Destination, cpDestinationIsFile in FOptions, cpCreateBackup in FOptions ); EventualFailure ( li_Error , '' ); End ; function TExtFileCopy.EventualFailure ( const ai_Error : Integer ; as_Message : AnsiString ):Boolean; begin Result := True ; if ( ai_Error <> 0 ) then Begin inc ( FErrors ); if assigned ( FOnFailure ) then Begin FOnFailure ( Self, ai_Error, as_Message, Result ); End ; End ; End ; procedure TExtFileCopy.InternalFinish ( const as_Source, as_Destination : String ); begin if assigned ( @FOnSuccess ) then Begin FOnSuccess ( Self, as_Source, as_Destination, FErrors ); End ; End ; procedure TExtFileCopy.CopySourceToDestination; var lb_Continue : Boolean ; begin Finprogress := true; FSizeTotal := 0 ; FErrors := 0 ; FSizeProgress := 0 ; if ( not FileExists ( FSource ) and not DirectoryExists ( FSource )) Then Exit ; if not DirectoryExists ( FDestination ) and not fb_CreateDirectoryStructure ( FDestination ) Then Exit ; try if ( DirectoryExists ( FSource )) Then Begin lb_Continue := fb_InternalCopyDirectory ( FSource, FDestination, FFilter, not ( cpNoStructure in FOptions ), cpDestinationIsFile in FOptions, cpCopyAll in FOptions, cpCreateBackup in FOptions, Self ); End Else Begin lb_Continue := fb_InternalCopyFile ( FSource, FDestination, cpDestinationIsFile in FOptions, cpCreateBackup in FOptions, Self ); End ; finally FinProgress := false; End ; end; {TExtFilePartialCopy} constructor TExtFilePartialCopy.Create(AOwner :Tcomponent); begin inherited Create(AOwner); FExcludeReading := False ; end; function TExtFilePartialCopy.BeforeCopyBuffer ( var li_SizeRead, li_BytesTotal : Longint ) : Boolean ; var li_pos, li_i : Longint ; Begin Result := inherited BeforeCopyBuffer ( li_SizeRead, li_BytesTotal ); if FExcludeReading and ( FExcludeStart <> '' ) and ( FExcludeEnd <> '' ) Then Begin li_pos := 0 ; li_i := 0 ; while li_pos < li_SizeRead do if lb_ExcludedFound then Begin End Else Begin End; end; End ; procedure TExtFilePartialCopy.AfterCopyBuffer ; Begin End ; function TExtFilePartialCopy.BeforeCopy : Boolean ; Begin Result := inherited BeforeCopy (); if FExcludeReading and ( FExcludeStart <> '' ) and ( FExcludeEnd <> '' ) Then Begin // lpch_excludeStart := fs_HexToString ( FExcludeStart ); // lpch_excludeEnd := fs_HexToString ( FExcludeEnd ); End ; End ; procedure Register; begin RegisterComponents('Extended', [TExtFileCopy]); end; initialization {$i U_ExtFileCopy.lrs} end.