我正在尝试复制目录:
procedure CopyBigDirWithSubdirs;
{$IOCHECKS ON}
begin
try
TDirectory.Copy(SrcPath, DstPath);
except
on E: EInOutError do something
end;
end;
就我而言,检查磁盘已满情况至关重要,我希望捕获 EInOutError 异常可以解决我的问题。但据我所知,TDirectory 方法根本不通知这种情况。情况更糟,因为 TDirectory.copy 可以写入部分子目录,面临磁盘已满情况并终止,因此我必须检查整个目录树以确保我的目录被正确复制。有人知道更好的解决方案吗?
答案 0 :(得分:2)
{$IOCHECKS ON}
在这里不相关。这适用于传统的 Pascal I/O。同样,对于 EInOutError
,您永远不会从 IOUtils
单元中的函数中得到它。
这里真正的问题是,TDirectory.Copy
与 IOUtils
的大部分内容一样,被设计破坏了。 TDirectory.Copy
中似乎没有实现任何错误检查。值得一提的是,我工作场所的规则是,不得在我们的代码中使用 IOUtils
。
您要么自己编写包含一些错误检查的代码,要么找到第三方库来完成这项工作。
当然在 Windows 上,您应该使用 IFileOperation
来执行此操作。作为一个好处,您甚至可以显示标准的系统进度对话框。而且由于代码是由系统提供的,而不是由 Embarcadero 提供的,因此您可以期待它的工作。
如果您需要对其他平台的支持,那么您可能需要更加努力地找到合适的代码。
答案 1 :(得分:0)
由于使用 IFileOperation 接口看起来是我基于它编写的函数的最实用的解决方案:
function CopyItem(const Src, Dest: string ): HRESULT;
const
FOF_SILENT = $0004;
FOF_NOCONFIRMATION = $0010;
FOF_NOCONFIRMMKDIR = $0200;
FOF_NOERRORUI = $0400;
FOF_NO_UI =(FOF_SILENT or FOF_NOCONFIRMATION or FOF_NOERRORUI or FOF_NOCONFIRMMKDIR); // don't display any UI at all
var
lFileOperation: IFileOperation;
psiFrom: IShellItem;
psiTo: IShellItem;
opAborted : longbool;
begin
//We probably don't need to call CoInitializeEx/CoUninitialize pair as it could have been called by Delphi library
CoInitializeEx(nil, COINIT_APARTMENTTHREADED or COINIT_DISABLE_OLE1DDE);
// check arguments and create the IFileOperation interface,
if (Src='') or (Dest='') then Result := E_INVALIDARG
else Result := CoCreateInstance(CLSID_FileOperation, nil, CLSCTX_ALL, IFileOperation, lFileOperation);
// Set the operation flags. Turn off all UI from being shown to the user
if Succeeded(Result) then Result := lFileOperation.SetOperationFlags(FOF_NO_UI);
// Create IShellItem-s from the supplied source and dest paths.
if Succeeded(Result) then Result := SHCreateItemFromParsingName(PWideChar(wideString(Src)),
nil, IShellItem, psiFrom);
if Succeeded(Result) then Result := SHCreateItemFromParsingName(PWideChar(wideString(Dest)),
nil, IShellItem, psiTo);
// This method does not copy the item, it merely declares the item to be copied
if Succeeded(Result) then Result := lFileOperation.CopyItem(psiFrom, psiTo, nil, nil);
// This method is called last to execute those actions that have been specified earlier
if Succeeded(Result) then Result := lFileOperation.PerformOperations;
// Check now if the operation was aborted by the system
if Succeeded(Result) then
begin
lFileOperation.GetAnyOperationsAborted(opAborted);
if opAborted then Result := ERROR_WRITE_FAULT;
end;
CoUninitialize;
end;
正如您从代码中看到的,解决方案并不完整,因为在磁盘已满错误的情况下(我对 lFileOperation 进行所有这些摆弄的原因) PerformOperations 返回 S_OK (!!!) 并且我只能通过调用 GetAnyOperationsAborted 找到错误它没有准确指定错误条件,而只是设置 opAborted 标志。那我就得猜一下堕胎的真实案例了。