有些文件可以使用,有些则没有。
var
Src : integer;
FileDate : LongInt;
begin
Src:=FileOpen(SrcPath,fmOpenRead);
FileDate:=FileGetDate(Src); // Crash here with FileDate = -1
...
FileSetDate(Dest,FileDate);
我已检查过有效文件的属性,有些则没有,但它们是相同的。
“安全”相同。
“Src”是有效的Integer,适用于那些有效的和无效的。
我唯一能看到的是,那些没有的完整路径可以是130个字符或更长。但我改名为一些文件夹,并将其缩短为118,但仍然没有好处。
让我感到困惑。在一个2000+文件复制过程中,在这个FileGetDate的同一子文件夹崩溃中只有149个。
有什么建议吗?
由于
答案 0 :(得分:2)
对FileGetDate
的调用返回-1。 documentation说明了这一点:
如果句柄无效,则返回值为-1。
换句话说,您对FileOpen
的调用返回的句柄无效。您不检查代码中的任何错误。您的代码假设所有调用都成功。 FileOpen
的失败模式是它返回-1。您没有检查FileOpen
的返回值。您必须添加代码才能执行此操作。
请注意FileOpen
的文档说:
注意:我们不鼓励使用非本地Delphi语言文件处理程序,如FileOpen。这些例程映射到系统 例程和返回OS文件句柄,而不是普通的Delphi文件变量。 这些是低级文件访问例程。用于普通文件操作 请改用AssignFile,Rewrite和Reset。
因此,即使是古老的传统Pascal I / O也优先于FileOpen
。
坦率地说,如果您想使用文件并获得有意义的错误诊断,则应使用Win32 API。致电CreateFile
,如果失败,请检查GetLastError
以找出原因。有很多方法可以使文件打开请求失败,而且实际上只有你可以找出文件的原因。我们手边没有文件,只有你这样做。
最后,您说您正在编写文件复制例程。系统已经提供了这样的东西,你最好不要使用它。你正在花费大量精力重新发明轮子。更重要的是,编写好的文件复制功能很难。已知系统提供的那个可以工作。你的版本可能会低劣。
要复制单个文件,您可以使用CopyFile
或CopyGFileEx
。但是您要复制多个文件,而SHFileOperation
就是API。
答案 1 :(得分:0)
3个想法,
首先是其他东西对该文件具有独占访问权限,而您无论如何都无法打开它。检查您打开的文件句柄是否有效。
第二种情况是,某些文件上可能有非常损坏的时间戳。我不知道它是怎么发生的,我只是知道它确实发生了。
最后,根据Linux上的文档,-1是一个有效的日期值,你没有提到你的源文件存储在哪个文件系统。
答案 2 :(得分:0)
以下是Delphi 5中FileGetDate()
的实现:
function FileGetDate(Handle: Integer): Integer;
var
FileTime, LocalFileTime: TFileTime;
begin
if GetFileTime(THandle(Handle), nil, nil, @FileTime) and
FileTimeToLocalFileTime(FileTime, LocalFileTime) and
FileTimeToDosDateTime(LocalFileTime, LongRec(Result).Hi,
LongRec(Result).Lo) then Exit;
Result := -1;
end;
这是 3 在任何给定输入文件句柄上可能发生的不同故障点:
GetFileTime()
失败了吗?
除非FileOpen()
失败(你没有检查它 - 如果它无法打开文件,它会返回-1
),那么#1或#不太可能(但不是不可能) 2失败了。但#3确实有一个记录的警告:
MS-DOS日期格式只能代表1980年1月1日到12月31日之间的日期;如果输入文件时间超出此范围,则此转换将失败。
在2108及更高版本中,您不太可能遇到带有时间戳的文件,但您肯定会在1979年及更早的版本中遇到带有时间戳的文件。
所有4个函数(计算CreateFile()
内部调用的FileOpen()
函数)都会通过GetLastError()
报告错误代码,因此您可以执行此操作:
var
Src : integer;
FileDate : LongInt;
begin
Src := FileOpen(SrcPath, fmOpenRead);
Win32Check(Src <> -1);
FileDate := FileGetDate(Src);
Win32Check(FileDate <> -1);
...
Win32Check(FileSetDate(Dest, FileDate) = 0);
如果输入参数为false,则 Win32Check()
调用RaiseLastWin32Error()
。 RaiseLastWin32Error()
引发EOSError
异常,其中包含ErrorCode
属性中的实际错误代码。
如果FileGetDate()
失败,显然你不知道哪个Win32功能实际上失败了。这就是调试器发挥作用的地方。在项目选项中启用调试DCU,以允许您进入VCL / RTL源代码。查找失败的文件,在其上调用FileGetDate(),并逐步查看其源代码,看看这三个API函数实际上是否失败。
同样适用于FileSetDate()
,它也在内部调用3个API函数:
function FileSetDate(Handle: Integer; Age: Integer): Integer;
var
LocalFileTime, FileTime: TFileTime;
begin
Result := 0;
if DosDateTimeToFileTime(LongRec(Age).Hi, LongRec(Age).Lo, LocalFileTime) and
LocalFileTimeToFileTime(LocalFileTime, FileTime) and
SetFileTime(Handle, nil, nil, @FileTime) then Exit;
Result := GetLastError;
end;
如果FileSetDate()
失败,那是因为:
SetFileTime()
失败了吗?