-1

有些文件可以使用,有些则不能。

var
  Src : integer;
  FileDate : LongInt;
begin
  Src:=FileOpen(SrcPath,fmOpenRead);
  FileDate:=FileGetDate(Src); // Crash here with FileDate = -1
  ...
  FileSetDate(Dest,FileDate);

我已经检查了有效文件和无效文件的属性,它们是相同的。

与“安全”相同,相同。

“Src”是一个有效的整数,适用于那些工作的和不工作的。

我唯一能看到的是那些没有的完整路径可以是 130 个字符或更长。但是我重命名了一些文件夹并将其缩短为 118,但仍然没有好处。

让我很困惑。在 2000 多个文件复制过程中,在这个 FileGetDate 中只有 149 个都在同一个子文件夹中崩溃。

有什么建议么?

谢谢

4

3 回答 3

2

调用FileGetDate返回 -1。文档是这样说的:

如果句柄无效,则返回值为 -1。

换句话说,您调用返回的句柄FileOpen是无效的。您不检查代码中的任何错误。您的代码假设所有调用都成功。的失败模式FileOpen是它返回-1。您没有检查FileOpen. 您必须添加代码才能这样做。

请注意,文档FileOpen说:

注意:我们不鼓励使用非本地 Delphi 语言文件处理程序,例如 FileOpen。这些例程映射到系统例程并返回 OS 文件句柄,而不是正常的 Delphi 文件变量。这些是低级文件访问例程。对于正常的文件操作,请改用 AssignFile、Rewrite 和 Reset。

因此,即使是古老的遗留 Pascal I/O 也比FileOpen.

坦率地说,如果您想处理文件并获得有意义的错误诊断,您应该使用 Win32 API。打电话CreateFile,如果失败,检查GetLastError找出原因。文件打开请求失败的方式有很多种,实际上只有您才能弄清楚文件的原因是什么。我们手头没有文件,只有你有。

最后,您说您正在编写一个文件复制例程。系统已经提供了这样的东西,你最好使用它。您正在花费大量精力重新发明轮子。更重要的是,编写一个好的文件复制功能很难。系统提供的那个是已知的。你的版本很可能是劣质的。

要复制单个文件,您可以使用CopyFileCopyGFileEx。但是您正在复制多个文件,并且SHFileOperation是用于此目的的 API。

于 2013-10-13T07:18:32.113 回答
0

3个想法,

首先是其他东西对文件具有独占访问权,无论如何您都无法打开它。然后检查您打开的文件句柄是否有效。

第二个是一些文件可能有非常损坏的时间戳。我不知道它是怎么发生的,我只知道它确实发生了。

最后,根据 Linux 上的文档,-1 是一个有效的日期值,您没有提及您的源文件存储在哪个文件系统上。

于 2013-10-12T23:59:32.120 回答
0

下面是FileGetDate()Delphi 5 中的实现:

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 个不同的故障点:

  1. GetFileTime()失败了吗?

  2. FileTimeToLocalFileTime()失败了吗?

  3. FileTimeToDosDateTime()失败了吗?

除非FileOpen()失败(您没有检查它 --1如果它无法打开文件,它会返回),那么 #1 或 #2 不太可能(但并非不可能)失败。但是#3确实有一个记录在案的警告:

MS-DOS 日期格式只能表示 1/1/1980 和 12/31/2107 之间的日期;如果输入文件时间超出此范围,则此转换失败。

您不太可能遇到时间戳为 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);

Win32Check()RaiseLastWin32Error()如果输入参数为假,则调用。在其属性中RaiseLastWin32Error()引发EOSError包含实际错误代码的异常。ErrorCode

如果FileGetDate()失败,显然你不会知道哪个 Win32 函数实际上失败了。这就是调试器发挥作用的地方。在您的项目选项中启用调试 DCU 以允许您单步执行 VCL/RTL 源代码。找到一个失败的文件,对其调用 FileGetDate(),并逐步查看其源代码,看看这三个 API 函数是否真的失败了。

同样 for 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()失败,是不是因为:

  1. DosDateTimeToFileTime()失败的?

  2. LocalFileTimeToFileTime()失败的?

  3. SetFileTime()失败了吗?

于 2015-06-28T05:36:56.817 回答