1. Memory Stream and File Stream have a problem overwriting files on a
network. They are not read-only files. Overwriting the same files on a local
drive works fine.
2. LZCopy works great most of the time, except it gets intermittent "invalid
souce file handle" for no apparent reason.
3. Shell to xcopy would work great except it can't seem to handle spaces in
the file names (even on Win2k) and DOS windows popup with each file transfer
(I need no popups). Does anyone have a list of all the xcopy error codes?
4. TShFileOpStruct seems to be the most reliable method, but is very slow
and it pops up a window to replace files. I need it to overwrite files by
default without popping up a window. Does anyone have a list of all the
TshFileOpStruct error codes? How about all the operating mode switches?
I skipped the "block read-write" method since it is the archaic way of
copying files.
Here is the source code I used for these, including 2 methods of invoking
LZCopy (1 of which does not read read-only files!). Note that for methods
that did not save the file date, I invoke a function to copy the original
file date (at the end of this post), though I wish there was a simpler
function without having to open the files again.
{memory stream}
{cannot overwrite some files on a network}
function filecopya(const sourcepath, targetpath: string): integer;
var
memstream: tmemorystream;
ferror: integer;
begin
{ progressmsg.lines.add('STARTING FILECOPY A'); }
ferror:= 0;
memstream:= tmemorystream.create;
try
try
if allmsgon then progressmsg.lines.add('Reading from source file>
'+sourcepath);
memstream.LoadFromFile(sourcepath);
if allmsgon then progressmsg.lines.add('Writing to target file>
'+targetpath);
memstream.SaveToFile(targetpath);
ferror:= copydate(sourcepath,targetpath);
if allmsgon then progressmsg.lines.add('Copying attributes to>
'+targetpath);
if ferror = 0 then begin
ferror:= filesetattr(targetpath,filegetattr(sourcepath));
if ferror <> 0 then ferror:= 3;
end
else ferror:= 4;
except
on EFOpenError do ferror:= 1;
on EFCreateError do ferror:= 2;
else
ferror:= 6;
end;
finally
memstream.Free;
end;
result:= ferror;
end;
{Filestream}
{cannot overwrite some files on a network}
function FileCopyb( const sourcepath, targetpath: String ): integer;
Var
source,target: TFileStream;
ferror: integer;
Begin
ferror:= 0;
try
try
if allmsgon then progressmsg.lines.add('Reading from source>
'+sourcepath);
source := tfilestream.create(sourcepath,fmopenread);
if allmsgon then progressmsg.lines.add('Writing to target>
'+targetpath);
target := tfilestream.create(targetpath,fmopenwrite or fmcreate);
if allmsgon then progressmsg.lines.add('Copying file to target>
'+targetpath);
target.copyfrom(source,0);
if allmsgon then progressmsg.lines.add('Copying date to target>
'+targetpath);
ferror:= filesetdate(target.handle,filegetdate(source.handle));
if ferror = 0 then begin
if allmsgon then progressmsg.lines.add('Copying attributes to
target> '+targetpath);
ferror:= filesetattr(targetpath,filegetattr(sourcepath));
end;
except
on EFOpenError do ferror:= 1;
on EFCreateError do ferror:= 2;
else
ferror:= 3;
end;
finally
target.free;
source.free;
end;
result:= ferror;
End;
{LZCopy}
{Cannot read read-only files(!), intermittent invalid souce file handle, see
better LZCopy method further down}
function filecopyc(sourcepath, targetpath: string): integer;
var
FromFile, ToFile: File;
ferror: integer;
begin
ferror:= 0;
AssignFile(FromFile, sourcepath); { Assign FromFile to FromFileName }
AssignFile(ToFile, targetpath); { Assign ToFile to ToFileName }
try
try
if allmsgon then progressmsg.lines.add('Opening source> '+sourcepath);
Reset(FromFile); { Open file for input }
except
ferror:= 1;
end;
if ferror = 0 then try
if allmsgon then progressmsg.lines.add('Opening target> '+targetpath);
Rewrite(ToFile); { Create file for output }
except
ferror:= 2;
end;
if ferror = 0 then try {copying file}
if allmsgon then progressmsg.lines.add('Copying source to target>
'+targetpath);
ferror:= LZCopy(TFileRec(FromFile).Handle, TFileRec(ToFile).Handle);
if ferror < 0 then case ferror of
LZERROR_BADINHANDLE : ferror:= 11;
LZERROR_BADOUTHANDLE : ferror:= 12;
LZERROR_BADVALUE : ferror:= 13;
LZERROR_GLOBALLOC : ferror:= 14;
LZERROR_GLOBLOCK : ferror:= 15;
LZERROR_READ : ferror:= 16;
LZERROR_UNKNOWNALG : ferror:= 17;
LZERROR_WRITE : ferror:= 18;
end
else ferror:= 0;
except
ferror:= 6;
end;
finally
try
CloseFile(ToFile); { Close ToFile }
except
end;
try
CloseFile(FromFile); { Close FromFile }
except
end;
end;
if ferror = 0 then ferror:= copydate(sourcepath,targetpath);
if ferror = 0 then begin
if allmsgon then progressmsg.lines.add('Copying attributes to target>
'+targetpath);
ferror:= filesetattr(targetpath,filegetattr(sourcepath));
end;
result:= ferror;
end; {filecopyc}
{Shell to xcopy}
{cannot handle spaces in filenames, annoying windows pop up}
function FileCopyd(const sourcepath, targetpath: string): integer;
var
SEInfo: TShellExecuteInfo;
ExitCode: DWORD;
ExecuteFile: string;
begin
ExecuteFile:='c:\winnt\system32\xcopy.exe';
FillChar(SEInfo, SizeOf(SEInfo), 0);
SEInfo.cbSize := SizeOf(TShellExecuteInfo);
with SEInfo do begin
fMask := SEE_MASK_NOCLOSEPROCESS;
Wnd := Application.Handle;
lpFile := PChar(ExecuteFile);
{contains the
application parameters.
R:overwrite readonly, H:copy hidden/system, Y:overwrite, Q:quiet, K:copy
attributes, X:copy audit settings}
lpParameters := PChar('/hrkqxy '+sourcepath+' '+targetpath);
{specifies the
name of the working directory.
If ommited, the current directory is used.}
// lpDirectory := PChar(insertnameofstartdirectoryhere);
nShow := SW_SHOWNORMAL;
end;
if ShellExecuteEx(@SEInfo) then begin
repeat
Application.ProcessMessages;
GetExitCodeProcess(SEInfo.hProcess, ExitCode);
until (ExitCode <> STILL_ACTIVE) or Application.Terminated;
end
else ShowMessage('Error starting Calc!');
progressmsg.lines.add('EXIT CODE> '+floattostr(exitcode));
result:= exitcode;
end; {filecopyd}
{TShFileOpStruct}
{very slow, annoying confirmation windows pop up}
function filecopye(sourcepath, targetpath: string; Protect: boolean):
integer;
{ Copies files or directory to another directory. }
{protect must be false or will add "copy of"}
var
F: TShFileOpStruct;
tmp1, tmp2: string;
ferror: integer;
begin
ferror:= 0;
FillChar(F, SizeOf(F), #0);
F.Wnd := 0;
F.wFunc := FO_COPY;
{ Add an extra null char }
tmp1 := sourcepath + #0;
tmp2 := targetpath + #0;
try
if allmsgon then progressmsg.lines.add('Opening source> '+sourcepath);
F.pFrom := PChar(tmp1);
except
ferror:= 1;
end;
if ferror= 0 then try
if allmsgon then progressmsg.lines.add('Opening target> '+targetpath);
F.pTo := PChar(tmp2);
except
ferror:= 2;
end;
if ferror = 0 then try
if allmsgon then progressmsg.lines.add('Copying source to target>
'+targetpath);
if Protect then F.fFlags := FOF_RENAMEONCOLLISION or FOF_SIMPLEPROGRESS
else F.fFlags := FOF_SIMPLEPROGRESS;
except
ferror:= 6;
end;
F.fAnyOperationsAborted := False;
F.hNameMappings := nil;
Result := ShFileOperation(F);
end; {filecopye}
{LZCopy method 2 (better than LZCopy method 1)}
{intermittent invalid souce file handle}
function filecopyf(sourcepath,targetpath : string) : integer;
var
sourcefile, targetfile : integer;
ferror: integer;
Msg: string;
begin
ferror:= 0;
try
try
if allmsgon then progressmsg.lines.add('Opening source> '+sourcepath);
sourcefile := FileOpen(sourcepath,0); { Open ReadOnly = 0,
Write=1, Readwrite=2}
except
ferror:= 1;
end;
if ferror = 0 then try
if allmsgon then progressmsg.lines.add('Opening target> '+targetpath);
targetfile := FileCreate(targetpath);
except
ferror:= 2;
end;
if ferror = 0 then begin
if allmsgon then progressmsg.lines.add('Copying source to target>
'+targetpath);
ferror := LZCopy(sourcefile,targetfile);
end;
finally
FileClose(sourcefile);
FileClose(targetfile);
end;
if ferror < 0 then case ferror of
LZERROR_BADINHANDLE : ferror:= 11;
LZERROR_BADOUTHANDLE : ferror:= 12;
LZERROR_BADVALUE : ferror:= 13;
LZERROR_GLOBALLOC : ferror:= 14;
LZERROR_GLOBLOCK : ferror:= 15;
LZERROR_READ : ferror:= 16;
LZERROR_UNKNOWNALG : ferror:= 17;
LZERROR_WRITE : ferror:= 18;
end
else ferror:= 0;
if ferror = 0 then begin
if allmsgon then progressmsg.lines.add('Copying attributes to target>
'+targetpath);
ferror:= filesetattr(targetpath,filegetattr(sourcepath));
end;
result := ferror;
end;
function filecopy(const sourcepath, targetpath: string): integer;
begin
{ progressmsg.lines.add('STARTING CURRENTSAVE'+inttostr(currentsave)); }
case currentsave of
1: filecopy:= filecopya(sourcepath,targetpath);
2: filecopy:= filecopyb(sourcepath,targetpath);
3: filecopy:= filecopyc(sourcepath,targetpath);
4: filecopy:= filecopyd(sourcepath,extractfiledir(targetpath));
5: filecopy:= filecopye(sourcepath,extractfiledir(targetpath),false);
6: filecopy:= filecopyf(sourcepath,targetpath);
end;
end;
{for copy methods that don't keep the original date automatically}
function copydate(source,target: string): integer;
var
shandle,thandle: integer;
ferror: integer;
begin
ferror:= 0;
try
try
if allmsgon then progressmsg.lines.add('Opening file to read date
from> '+targetpath);
shandle := FileOpen(source, 0);
if allmsgon then progressmsg.lines.add('Opening file to write date to
target> '+targetpath);
thandle := FileOpen(target, 1);
if allmsgon then progressmsg.lines.add('Copying date to target>
'+targetpath);
ferror:= filesetdate(thandle,filegetdate(shandle));
if ferror <> 0 then ferror:= 4;
except
ferror:= 4;
end;
finally
fileclose(thandle);
fileclose(shandle);
end;
result:= ferror;
end;
>I have tried several methods of copying files in Delphi. ALL of them have
>shortcomings. Of the sortcomings I list here, can any be eliminated?
>
>1. Memory Stream and File Stream have a problem overwriting files on a
>network. They are not read-only files. Overwriting the same files on a local
>drive works fine.
>
I would be inclined to Free the streams before setting the attributes, but it
might not make any difference.
I don't know whether THandleStream is any better, or even the mmio file
functions (they have their own buffers).
I have had problems on some network file copy where it errors with error code
103 - "Too many semaphores" whatever _that_ means.
I have a sneaking feeling that there is some network file cache which does not
get flushed.
Alan Lloyd
alang...@aol.com
You could try to include FOF_NOCONFIRMATION with the Flags.
Error codes should be in the "win32 error code listing" in win32.hlp
PS: There is also the straight forward CopyFile() function in
Windows.pas.
HTH
-ThomasN
>I skipped the "block read-write" method since it is the archaic way of
>copying files.
Does it suffer from any of the problems with the other methods?
"The runtime library does not provide any routines for copying a file.
However, you can directly call the Windows API CopyFile function to copy a
file. Like most of the Delphi runtime library file routines, CopyFile takes
a filename as a parameter, not a Window Handle. When copying a file, be
aware that the file attributes for the existing file are copied to the new
file, but the security attributes are not. CopyFile is also useful when
moving files across drives because neither the Delphi RenameFile function
nor the Windows API MoveFile function can rename/move files across drives. "
-Mike
"Thomas Nelvik" <thomas...@chello.no> wrote in message
news:mxvW6.6597$qR5.5...@news01.chello.no...
--
Blade
"Mad Martian" <ne...@madmartian.com> wrote in message
news:jasW6.178454$p33.3...@news1.sttls1.wa.home.com...
But if you are having trouble with file handles...then BlockRead and
BlockWrite with a record size of 1 is the idea of the first message.
This is from Delphi's help, not "Win32 Programmers reference"
(win32.hlp).
Write "CopyFile" in your editor and push F1 to get to the correct
page.
The WinAPI CopyFile() does truly _not_ copy security attributes.
If this is needed, then use the CopyFileEx(), available on WinNT
platform.
HTH
-ThomasN
>I have tried several methods of copying files in Delphi.
If the files aren't too large, you can use LoadFromFile and
SaveToFile.
Filemode:=0:
When creating first form.
--
Regards
Ingolf
"Mad Martian" <ne...@madmartian.com> wrote in message
news:jasW6.178454$p33.3...@news1.sttls1.wa.home.com...
I tried the following:
res:= copyfileex(pchar(sourcepath),pchar(targetpath),null,null,false,0);
and got the error "incompatable types: Variant and Pointer" with the cursor
between the 2 nulls. What am I doing wrong?
Also, do you know the difference between "Copyfile", "CopyfileA", and
"CopyfileW"?
Thanks,
-Mike
"Thomas Nelvik" <thomas...@chello.no> wrote in message
news:gVHW6.6639$qR5.5...@news01.chello.no...
In pascal, a standard null-pointer is called "NIL".
> Also, do you know the difference between "Copyfile", "CopyfileA",
and
> "CopyfileW"?
With most of the windows API functions there is an Ansi- and a
WideChar
version, hence the "A" or "W" suffix. Only difference is that the one
expect AnsiStrings and the other WideStrings as parameters. If you see
the "Windows.pas" unit, you find that Delphi uses the Ansi-version as
"default", that is "CopyFile" _means_ "CopyFileA" , and that will do
in most cases.
Regards
-ThomasN
"Ingolf" <DONT_SPA...@musling.dk> wrote in message
news:YFqX6.3982$VQ4.6...@news010.worldonline.dk...
"Jan Philips" <jud.mccra...@mindspring.com> wrote in message
news:65cnitsiniop6t2ag...@4ax.com...