3

このコードを考えると:

  FN := 'c:\temp\test_file.log';
  AFile := TFile.Open(FN, TFileMode.fmOpenOrCreate, TFileAccess.faReadWrite, TFileShare.fsRead);
  try
    with TFile.OpenRead(FN) do
    try

    finally
      Free;
    end;

  finally
    AFile.Free;
  end;

TFile.OpenRead(FN) 行で開こうとするとエラーが発生します。
ここに画像の説明を入力

使用:

with TFile.Open('c:\temp\test_file.log', TFileMode.fmOpen, TFileAccess.faRead, TFileShare.fsRead) do
try

finally
  Free;
end;

も同じエラーになります。同様に:

  FS := TFileStream.Create('c:\temp\test_file.log', fmOpenRead or fmShareDenyWrite);
  try

  finally
    FS.Free;
  end;

ただし、メモ帳で (読み取り専用として) ファイルを問題なく開くことができます。または、最初の TFileShare.fsRead を TFileShare.fsNone に変更すると、期待どおりに (メモ帳で) 開くことができません。

ただし、このダミー アプリの 2 つのインスタンスを実行すると、最初の 1 つが TFileShare.fsRead で開かれ、開くことができます。同じアプリケーションでファイルを 2 回開くことはできませんか? 正しくないようです。

最初にファイルを開くと:

  FS := TFileStream.Create('c:\temp\test_file.log', fmOpenReadWrite or fmShareDenyWrite);
  try

  finally
    FS.Free;
  end;

上記の方法で(fsReadを使用して)もう一度開くことができます。紛らわしいのは、TFile.Open コードをステップ実行することです。最終的には、上記の TFileStream.Create とまったく同じコードを実行します。

最後にメモ。一番上の(最初の)方法を使用して開いたが、それを「グローバル」変数に割り当てた場合、内部 TFile.OpenRead(FN) 呼び出しを削除してから、別のボタンをクリックしてファイルを開こうとすると、エラーが持続します。これは、ネストされた呼び出しに関連していないことを証明しています。

4

3 に答える 3

1

Windows のアクセス権は、TFileStream.Create から呼び出される FileCreate と FileOpen の Mode から抽出されます。
CreateFileはここで ShareMode[(Mode and $F0) shr 4] で呼び出されます。

TFileMode.fmOpenOrCreate は
TFileStream.Create(Path, fmCreate, LFileStrmShare);を呼び出します。ファイルが存在しません。

行動を示すことができます

function OpenReadShareALL(const Path: string): TFileStream;
begin
  If FileExists(Path) then
    begin
      try
        Result := TFileStream.Create(Path, fmOpenRead or fmShareDenyNone);
        // will work too at lest up to XE since rights are ignored in oder versions
        //Result := TFileStream.Create(Path, fmOpenRead or fmShareDenyNone,fmShareExclusive);
      except
        on E: EFileStreamError do
          raise EInOutError.Create(E.Message);
      end;
    end;
end;



var
  FN:String;
  AFile:TFileStream;
begin
  FN := 'c:\temp\test_file.log';
 // this will lock file at least until Delphi XE if file has to be created
 //AFile := TFile.Open(FN, TFileMode.fmOpenOrCreate, TFileAccess.faReadWrite, TFileShare.fsReadWrite);


 // the following will work
 if Fileexists(FN) then
    AFile := TFileStream.Create(fn,fmOpenRead or fmOpenWrite or fmShareDenyNone)
 else
    AFile := TFileStream.Create(fn,fmCreate  or fmShareDenyNone);      

 // won't work if file does not exists , and will not work with existing file up to at least Delphi XE (fixed in XE 3 , maybe XE 2 too)
 //  AFile := TFileStream.Create(fn,fmCreate or fmOpenReadWrite ,fmShareDenyNone);
  try
    with OpenReadShareAll(FN) do
    try
      Showmessage('Worked');
    finally
      Free;
    end;

  finally
    AFile.Free;
  end;
end;

XE3 では、権限の無視は、fmCreate 以外のアクセス モードで修正されたようです。

inherited Create(FileOpen(AFileName, Mode or Rights));
于 2013-04-16T06:39:54.323 に答える
1

少なくとも Delphi 2010 までは、同様の問題があります。基本的な問題は、ファイルに「作成」フラグが設定されている場合、一部の共有フラグが考慮されないことです。あなたはそれについてもっと読むことができます

http://cc.embarcadero.com/Item/21636

少なくとも、フラグを「or」した「古いスタイル」のファイル作成を修正する必要があります。

于 2013-04-16T06:58:12.023 に答える