Board index » delphi » Copying files and dirs

Copying files and dirs

I'm a rather beginning Delphi programmer, but I must say Delphi's
documentation is not very helpful at that issue.

Is it really necessary to write own procedures for copying a whole
directory branch (using FindFirst and so on...) ??
Or is there a nice way to perform the task ?

Is there a windows counterpart for old pascal's:

Exec('c:\command.com', '/c xcopy /q /e /r /y c:\adir d:\adir'); ?

Please help if you can...
Martin.

 

Re:Copying files and dirs


Quote
>Is it really necessary to write own procedures for copying a whole
>directory branch (using FindFirst and so on...) ??
>Or is there a nice way to perform the task ?

Well, yes and no. The ShFileOperation will do lots of things for
you like moving, copying and deleting files and directories,
but sometimes you'll need to resort to FindFirst/FindNext.

Quote
>Is there a windows counterpart for old pascal's:

>Exec('c:\command.com', '/c xcopy /q /e /r /y c:\adir d:\adir'); ?

You can still do this with ShellExecute if you want:

ShellExecute(Handle, nil, 'c:\command.com',
  '/c xcopy /q /e /r /y c:\adir d:\adir', nil, SW_HIDE);

But you shouldn't hard-code "command.com" or it won't work under
Windows NT.
--
Jeremy Collins
Kansai Business Systems

(return address not altered 'coz I get spammed *whatever* I do!)

Re:Copying files and dirs


Quote
Martin R. wrote:
> I'm a rather beginning Delphi programmer, but I must say Delphi's
> documentation is not very helpful at that issue.

> Is it really necessary to write own procedures for copying a whole
> directory branch (using FindFirst and so on...) ??
> Or is there a nice way to perform the task ?

> Is there a windows counterpart for old pascal's:

> Exec('c:\command.com', '/c xcopy /q /e /r /y c:\adir d:\adir'); ?

> Please help if you can...
> Martin.

  Hi,
Try the procedure copyfile() in the unit fmxutils.
J.Michot

Re:Copying files and dirs


I agree, there should be a better way of doing this - but you can use the
principle of your code with the ShellExcute function (include ShellAPI in Uses
clause)

Charles Johnson

Re:Copying files and dirs


Martin,

If you're using Delphi 2, 3, or 4, you can use SHFileOperation,
from the Win32 API. If you can't figure out how to use it after
going through the help file, drop me a note...

Ken
--
Ken White
kwh...@westelcom.com

Clipper Functions for Delphi
http://members.aol.com/clipfunc/

Quote
Martin R. wrote:

> I'm a rather beginning Delphi programmer, but I must say Delphi's
> documentation is not very helpful at that issue.

> Is it really necessary to write own procedures for copying a whole
> directory branch (using FindFirst and so on...) ??
> Or is there a nice way to perform the task ?

> Is there a windows counterpart for old pascal's:

> Exec('c:\command.com', '/c xcopy /q /e /r /y c:\adir d:\adir'); ?

> Please help if you can...
> Martin.

Re:Copying files and dirs


I have solved my problems, partially by using Delphi's own
functions, partially by using functions from the Windows unit
and partially by FindFirst, FindNext, FindClose...

Using ShellExecute didn't satisfy me because I had the feeling, that
Delphi doesn't wait for ShellExecute to complete
and if you have some subsequent calls like
ShellExecute(COPY) + ShellExecute(RENAME) + ... + ...
then they seem to run at the same time and that's definitely no good
for me, because the system wants to rename files that aren't copied
yet!
The worst thing is, that if you really want to code a clean 'CopyDir'
procedure then you probably have to code it recursively and that's
a real pain.

Re:Copying files and dirs


The message <35B3F66D.86A49...@westelcom.com>
  from  Ken White <kwh...@westelcom.com> contains these words:

Quote
> Martin,
> If you're using Delphi 2, 3, or 4, you can use SHFileOperation,
> from the Win32 API. If you can't figure out how to use it after
> going through the help file, drop me a note...

Ken,

I saw your suggestion above so I thought I'd try it.
Well it works, but there is a problem. I am using Delphi 3 and the
code below to copy big .avi files (3-30MB) from F:\ to D:\. D: has
300MB free space. The problem seems to be with the length of the
source filename.
If the part of the filename before the .avi extension is seven or
fewer characters the file copies and windows 95 produces the (as
advertised) progress dialog. If the name of the same file is eight
characters or
more I get a pop up box with the following message:-

                        "Error Copying File
                         FileSystem Error 1026"

The Win32 help implies but does not explicitly state that the function
should work with long file names. I tried the GetShortPathName call
but it made no difference. Error 1026 is not in the Win32 Help. I also
have some recent C code headers which I downloaded from Microsoft and
Error 1026 is not there either.

Can anybody tell me what I am doing wrong?

--
regards

Andreas

Here is my code
---------------
The code has shellAPI in the uses clause at the top, and
has a TOpenDialog, TSaveDialog, and two TLabel
components on a form.

var
  Form1: TForm1;
  FileOpStruct : TSHFileOpStruct;

implementation

{$R *.DFM}

{============
 Button1Click
 ============}
procedure TForm1.Button1Click(Sender: TObject);
begin
OpenDialog1.InitialDir:='F:\';
if not Opendialog1.Execute then exit;
Label1.Caption:=OpenDialog1.Filename; //check source file valid

SaveDialog1.Filename:=ExtractFileName(OpenDialog1.FileName);
SaveDialog1.InitialDir:='D:\' ;
if not SaveDialog1.execute then exit;
Label2.Caption:=SaveDialog1.Filename; //check destination file valid

{fill in the TSHFileOPstruct}
  FileOpStruct.Wnd:=0;                
  FileOpStruct.wFunc:=FO_COPY;
  FileOpStruct.pFrom:=Pchar(OpenDialog1.FileName);
  FileOpStruct.pTo:=Pchar(SaveDialog1.FileName);
  FileOpStruct.fFlags:=0;
  FileOpStruct.fAnyOperationsAborted:=False;
  FileOpStruct.hNameMappings:=nil;
  FileOpStruct.lpszProgressTitle:='';

{make the API call}
SHFileOperation(FileOpStruct);
end;

end.

Re:Copying files and dirs


Quote
Martin R. wrote:
> Using ShellExecute didn't satisfy me because I had the feeling, that
> Delphi doesn't wait for ShellExecute to complete
> and if you have some subsequent calls like
> ShellExecute(COPY) + ShellExecute(RENAME) + ... + ...

I think that Delphi provides facilities for performing file operations
like this, so you don't have to use ShellExecute. In addition, the app
waits for completion (since, currently, Win32 file IO is synchronous,
although I think some message based functions have recently been, or
will be added)

Incidentally, ShellExecute is obsolete. You should use CreateProcess.

ShellExecute and CreateProcess operate concurrently. If you want to wait
for the process to end, then you should use the API call
WaitForProcessExit, using the handle that CreateProcess passes you.

Quote
> The worst thing is, that if you really want to code a clean 'CopyDir'
> procedure then you probably have to code it recursively and that's
> a real pain.

Not necessarily. You could use a stringlist to hold a list of strings
containing the files you know about that haven't currently been copied.
Just go through the list, trating dirs and files appropriately, and then
repeat until there's nothing left in the list.

Have you thought about cases where the destination is a subdir of the
source? Naive code will recursively copy for ever into deeper and deeper
subdirs in some such cases.

MH.

Re:Copying files and dirs


Andreas,

Surround your filename with double quotes... For example, if you
want to copy sFileName:

sFileName := '"c:\program files\borland\delphi 3\images\myfile.avi"';

When you're dealing with a record (structure, in C-speak), you
should always set the entire record to known values before using
it:

FillChar(FileOpStruct, SizeOf(TSHFileOpStruct), 0);

Also, the Win32 API help file has an error in it... You should
terminate both the pFrom and pTo arguments with two null characters:

  FileOpStruct.pFrom:=Pchar(OpenDialog1.FileName) + #0;
  FileOpStruct.pTo:=Pchar(SaveDialog1.FileName) + #0;

This should fix the problem with SHFileOperation...

As far as the Windows error goes, try using this:

ShowMessage(SysErrorMessage(GetLastError));

Ken
--
Ken White
kwh...@westelcom.com

Clipper Functions for Delphi
http://members.aol.com/clipfunc/

Quote
Andreas Kyriacou wrote:

> The message <35B3F66D.86A49...@westelcom.com>
>   from  Ken White <kwh...@westelcom.com> contains these words:

> > Martin,

> > If you're using Delphi 2, 3, or 4, you can use SHFileOperation,
> > from the Win32 API. If you can't figure out how to use it after
> > going through the help file, drop me a note...

> Ken,

> I saw your suggestion above so I thought I'd try it.
> Well it works, but there is a problem. I am using Delphi 3 and the
> code below to copy big .avi files (3-30MB) from F:\ to D:\. D: has
> 300MB free space. The problem seems to be with the length of the
> source filename.
> If the part of the filename before the .avi extension is seven or
> fewer characters the file copies and windows 95 produces the (as
> advertised) progress dialog. If the name of the same file is eight
> characters or
> more I get a pop up box with the following message:-

>                         "Error Copying File
>                          FileSystem Error 1026"

> The Win32 help implies but does not explicitly state that the function
> should work with long file names. I tried the GetShortPathName call
> but it made no difference. Error 1026 is not in the Win32 Help. I also
> have some recent C code headers which I downloaded from Microsoft and
> Error 1026 is not there either.

> Can anybody tell me what I am doing wrong?

> --
> regards

> Andreas

> Here is my code
> ---------------
> The code has shellAPI in the uses clause at the top, and
> has a TOpenDialog, TSaveDialog, and two TLabel
> components on a form.

> var
>   Form1: TForm1;
>   FileOpStruct : TSHFileOpStruct;

> implementation

> {$R *.DFM}

> {============
>  Button1Click
>  ============}
> procedure TForm1.Button1Click(Sender: TObject);
> begin
> OpenDialog1.InitialDir:='F:\';
> if not Opendialog1.Execute then exit;
> Label1.Caption:=OpenDialog1.Filename; //check source file valid

> SaveDialog1.Filename:=ExtractFileName(OpenDialog1.FileName);
> SaveDialog1.InitialDir:='D:\' ;
> if not SaveDialog1.execute then exit;
> Label2.Caption:=SaveDialog1.Filename; //check destination file valid

> {fill in the TSHFileOPstruct}
>   FileOpStruct.Wnd:=0;
>   FileOpStruct.wFunc:=FO_COPY;
>   FileOpStruct.pFrom:=Pchar(OpenDialog1.FileName);
>   FileOpStruct.pTo:=Pchar(SaveDialog1.FileName);
>   FileOpStruct.fFlags:=0;
>   FileOpStruct.fAnyOperationsAborted:=False;
>   FileOpStruct.hNameMappings:=nil;
>   FileOpStruct.lpszProgressTitle:='';

> {make the API call}
> SHFileOperation(FileOpStruct);
> end;

> end.

Re:Copying files and dirs


The message <35B90F17.F81C4...@westelcom.com>
  from  Ken White <kwh...@westelcom.com> contains these words:

Quote
> Andreas,
> Surround your filename with double quotes... For example, if you
> want to copy sFileName:
> sFileName := '"c:\program files\borland\delphi 3\images\myfile.avi"';
> When you're dealing with a record (structure, in C-speak), you
> should always set the entire record to known values before using
> it:
> FillChar(FileOpStruct, SizeOf(TSHFileOpStruct), 0);
> Also, the Win32 API help file has an error in it... You should
> terminate both the pFrom and pTo arguments with two null characters:
>   FileOpStruct.pFrom:=Pchar(OpenDialog1.FileName) + #0;
>   FileOpStruct.pTo:=Pchar(SaveDialog1.FileName) + #0;
> This should fix the problem with SHFileOperation...
> As far as the Windows error goes, try using this:
> ShowMessage(SysErrorMessage(GetLastError));

Ken,

Many thanks for your suggestions, they were helpful in cracking
the problem, although the root of the fault lay elsewhere.

Here is what I have discovered.

1) The windows error number.
It would seem that error numbers for this function are a recent
introduction. I am using win95a with Internet Explorer 4.01. When
I uninstalled IE 4.01 the same error occured but the dialog box
contained a readable error message. The exact wording of the
massage differed as I tried my various experiments, but initialy it
claimed it could not find the file. (The source and destination
file had the same name so this was pretty useless).

2)The destination string that FileOpStruct.pTo points to is a directory.
I had assumed it should be a file name. This was the central fault in
the original program, which leaves the question of why it worked for
file names containing less than seven letters a complete mystery.

3)It stops working if you include a #0 on the end of the destination
string as in

            FileOpStruct.pTo:=Pchar('F:\ADIRECTORY\'+#0),

but it won't work without a #0 at the end of the source string.

            FileOpStruct.pFrom:=Pchar('D:\Mylongfile.avi'+#0)

4)Surrounding either the source or destination path in quotes also
stops it working.

I have attatched a functioning copy of my code at the bottom of the
page for anyone interested in experimenting with SHFileOperation.

--
regards

Andreas

Here is my Working Code
-----------------------
The code has shellAPI in the uses clause at the top, and
has a TButton,TOpenDialog, TSaveDialog, and two TLabel
components on a form.

var
  Form1: TForm1;
  FileOpStruct : TSHFileOpStruct;

implementation

{$R *.DFM}

{============
 Button1Click
 ============}
procedure TForm1.Button1Click(Sender: TObject);
var OutPutDir:string ;
begin
OpenDialog1.InitialDir:='F:\';
if not Opendialog1.Execute then exit;
Label1.Caption:=OpenDialog1.Filename; //check source file valid
SaveDialog1.InitialDir:='D:\' ;
Savedialog1.Filename:=ExtractFileName(OpenDialog1.Filename);
if not SaveDialog1.execute then exit;
OutPutDir:=ExtractFilePath(SaveDialog1.Filename);
Label2.Caption:=OutPutDir; //check destination dir valid

{fill in the TSHFileOPstruct}
  FileOpStruct.Wnd:=0;
  FileOpStruct.wFunc:=FO_COPY;
  FileOpStruct.pFrom:=Pchar(OpenDialog1.FileName+#0);
  FileOpStruct.pTo:=Pchar(OutPutDir);
  FileOpStruct.fFlags:=0;
  FileOpStruct.fAnyOperationsAborted:=False;
  FileOpStruct.hNameMappings:=nil;
  FileOpStruct.lpszProgressTitle:='';

{make the API call}
SHFileOperation(FileOpStruct);
end;
end.

Other Threads