-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のドキュメントには次のように記載されていることに注意してください。

: FileOpen などの非ネイティブ Delphi 言語ファイル ハンドラの使用はお勧めしません。これらのルーチンはシステム ルーチンにマップされ、通常の Delphi ファイル変数ではなく、OS ファイル ハンドルを返します。これらは、低レベルのファイル アクセス ルーチンです。通常のファイル操作では、代わりに AssignFile、Rewrite、および Reset を使用してください。

そのため、古いレガシー Pascal I/O でさえ、 よりも優先されFileOpenます。

率直に言って、ファイルを操作して意味のあるエラー診断を取得したい場合は、Win32 API を使用する必要があります。電話CreateFileして、失敗した場合は、そのGetLastError理由を確認してください。ファイルを開くリクエストが失敗する原因はたくさんありますが、現実的には、ファイルの原因を突き止めることができるのは自分だけです。私たちはファイルを手元に持っていません。あなただけが持っています。

最後に、ファイル コピー ルーチンを書いているとします。システムはすでにそのようなものを提供しており、それを使用する方がはるかに良いでしょう. 車輪の再発明に多くの労力を費やしています。さらに、優れたファイル コピー関数を作成するのは困難です。システムが提供するものは、機能することが知られています。あなたのバージョンは劣っている可能性があります。

単一のファイルをコピーするには、CopyFileまたはを使用できますCopyGFileEx。しかし、あなたは複数のファイルをコピーしてSHFileOperationおり、そのための API です。

于 2013-10-13T07:18:32.113 に答える
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 の日付形式は、1980 年 1 月 1 日から 2107 年 12 月 31 日までの日付のみを表すことができます。入力ファイルの時間がこの範囲外の場合、この変換は失敗します。

タイムスタンプが 2108 年以降のファイルに遭遇する可能性は低いですが、タイムスタンプが 1979 年以前のファイルに遭遇する可能性は確かにあります。

CreateFile()4 つのすべての関数 (内で呼び出される関数を数えます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()入力パラメーターが false の場合に呼び出します。プロパティに実際のエラー コードを含む例外を発生させRaiseLastWin32Error()ます。EOSErrorErrorCode

失敗した場合FileGetDate()、どの Win32 関数が実際に失敗したかは明らかにわかりません。そこでデバッガの出番です。Project Options で Debug DCUs を有効にして、VCL/RTL ソース コードにステップインできるようにします。失敗したファイルを見つけて FileGetDate() を呼び出し、そのソース コードをステップ実行して、3 つの 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()失敗した場合、それは次の理由によるものですか。

  1. DosDateTimeToFileTime()失敗した?

  2. LocalFileTimeToFileTime()失敗した?

  3. SetFileTime()失敗しましたか?

于 2015-06-28T05:36:56.817 に答える
0

3つの想い、

1 つ目は、他の何かがファイルへの排他的アクセス権を持っており、関係なく開くことができないということです。開いているファイルハンドルが有効であることを確認してください。

2 つ目は、一部のファイルのタイム スタンプが非常に破損している可能性があることです。それがどのように起こるかはわかりませんが、そうなることだけは知っています。

最後に、Linux のドキュメントによると、-1 は有効な日付値です。ソース ファイルが保存されているファイル システムについては言及していません。

于 2013-10-12T23:59:32.120 に答える