7

我正在尝试将来自其他应用程序(Proxifier)的会话日志记录到备忘录中。我试过使用命令:

procedure TForm1.TimerTimer(Sender: TObject);
begin
  Memo1.Lines.LoadFromFile('C:\PMASSH\Proxyfier\Profiles\Log.txt');
end;

但在某些时候我得到一个错误

在此处输入图像描述

你能帮我解决上面的问题吗?我真的很感激所有的答案。

谢谢

4

4 回答 4

7

其他程序以不允许其他进程读取的共享模式打开文件。这通常发生在其他应用程序正在写入文件时。

您对此无能为力。这是完全正常的行为,是可以预料的。您可以尝试检测错误,等待一小段时间,然后重试。

由于您已经在计时器上运行它,因此重试将会发生。所以也许你只需要抑制这些异常:

procedure TForm1.TimerTimer(Sender: TObject); 
begin
  try
    Memo1.Lines.LoadFromFile(...);
  except
    on EFOpenError do
      ; //swallow this error
  end;
end;

请注意,检测EFOpenError可能有点粗糙。也许还有其他导致该错误的故障模式。然而,作为第一遍,上面的代码是一个不错的开始。

于 2012-11-23T17:35:05.683 回答
5

大卫的回答是正确的。我只是想澄清为什么会这样。

答案就在代码中:

procedure TStrings.LoadFromFile(const FileName: string);
var
  Stream: TStream;
begin
  Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
  try
    LoadFromStream(Stream);
  finally
    Stream.Free;
  end;
end;

如您所见,访问该文件以进行共享,但不允许写入。您可以通过自己创建文件流来解决此问题:

Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);

然后使用Lines.LoadFromStream()方法将内容加载到备忘录中

请注意,在其他应用程序以独占模式(即不共享)打开文件的情况下,问题可能仍然存在,因此仍然需要像 David 的回答那样进行适当的异常管理。

于 2012-11-23T20:17:11.080 回答
2

您可以使用 ReadFile WinAPI 试试运气。在共享读取打开模式下,您将能够在最后一次文件缓冲区刷新时偷偷地读取文件的内容。如果另一个应用程序(Proxifier)使用 CreateFile WinAPI 和 FILE_SHARE_READ 共享模式打开文件,那么只要您使用 ReadFile API,您就可以打开它进行阅读。如果仍然打开共享,Standart LoadFromFile 方法将在这里不起作用,并且您将收到相同的“锁定”错误。

但这里有一个问题..您必须处理缓冲区、大小和句柄...您必须为文件分配一个句柄以供读取,使用该句柄获取文件大小,设置一个具有该大小的数组,执行读取该数组并分配,将该数组(无论如何)添加到备忘录中。WinAPI的纯用法。一些简单任务的工作......

下面是一个如何使用 WinAPI 处理文件的基本示例:

该其他应用程序的文件打开过程的关键假设:

var
  Form1: TForm1;
  logfile: Textfile;
  h: THandle;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin    
  // AssignFile(logfile, 'c:\deneme.txt');
  // Rewrite(logfile);

  h := CreateFile('C:\deneme.txt', GENERIC_WRITE, FILE_SHARE_READ, nil,
    CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

  Timer1.enabled := true;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  Timer1.enabled := false;

  // CloseFile(logfile);
  CloseHandle(h);
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
  str: AnsiString;
  p: pointer;
  buf: array of ansichar;
  written: cardinal;
begin
  // Writeln(logfile, 'denemeStr');

  str := 'denemeStr' + #13#10;
  p := pansichar(str);

  SetLength(buf, length(str));
  move(p^, buf[0], length(str));

  WriteFile(h, buf[0], length(buf), written, nil);
  FlushFileBuffers(h);
end;

如果它已被共享以供阅读,您可以通过以下方式阅读它:

procedure TForm1.Button1Click(Sender: TObject);
var
  h: THandle;
  buf: array of ansichar;
  size, read: cardinal;
begin
  Memo1.Lines.Clear;
  // Memo1.Lines.LoadFromFile('c:\deneme.txt');

  h := CreateFile('C:\deneme.txt', GENERIC_READ, FILE_SHARE_READ, nil,
    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  size := GetFileSize(h, nil);
  SetLength(buf, size);

  ReadFile(h, buf[0], size, read, nil);
  CloseHandle(h);
  Memo1.Lines.Add(pansichar(buf));
end;

希望这会有所帮助...

于 2012-11-23T19:49:26.547 回答
-1
procedure TForm1.TimerTimer(Sender: TObject);
begin
  Memo1.Lines.LoadFromFile('C:\PMASSH\Proxyfier\Profiles\Log.txt');//// read file path error if file notfound
// if trying to record 
  Memo1.Lines.SaveToFile(Path...);
end;
于 2014-10-15T09:11:04.987 回答