AssignFile():文件访问被拒绝。

3
我想在任何运行时刻创建一个 .txt 文件并向其中写入内容。为了实现这一点,我使用了 AssignFile() 函数。但是在文件已经存在的情况下,我遇到了问题。我会收到一个错误,上面写着:“文件访问被拒绝”。
为了更好地解释这个问题,看看这两个例子:
Ex1:如果我第一次调用 AssignFile() 函数时文件不存在,那么没问题!但是,如果文件存在,这就无法工作。
Ex2:如果我第二次调用 AssignFile() 函数(当第一次调用成功时),这也无法工作。
这是否是 AssignFile() 函数中的一个漏洞?
var
  myfile: TextFile;

  Procedure WriteFileContent(const MyTxtFile: string; MyNumber: DWORD);
  var
    F: TextFile;
  Begin
    If FileExists(MyTxtFile) Then
    Begin
      AssignFile(F, MyTxtFile);
      Rewrite(F);
      Writeln(F, '0x' + IntToHex(MyNumber,8));
      CloseFile(F);
    End;
  End;

begin
  try

    // Calling AssignFile() by first time
    AssignFile(myfile, 'myfile.txt');
    Rewrite(myfile);
    CloseFile(myfile);
    setfileattributes('myfile.txt', FILE_ATTRIBUTE_HIDDEN);

    Sleep(5000);

    // Calling AssignFile() by second time
    WriteFileContent('myfile.txt', 123456789);

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

为什么你没有指定文件的完整路径? - MartynA
你显然正在尝试访问一个你没有权限的文件。例如,如果你的程序安装在 C:\Program Files 中,并且正在尝试访问应用程序文件夹中的文件,则标准用户无法对其进行写入访问。你应该将文件写入用户配置文件夹中的一个文件夹中。Win32 API有函数可以确定用户配置文件夹的位置。 - Remy Lebeau
@MarcioGomes:根据您展示的代码,这是不可能的。除非您将应用程序作为一个非常受限制的用户运行,该用户没有对任何内容的写访问权限。始终使用绝对路径,并确保您的用户具有对其的写访问权限。 - Remy Lebeau
这是一个 bug 吗?不,错误在于你的理解。不要假设任何失败都是 bug。首先要反思自己。 - David Heffernan
1
如果您删除了setfileattributes('myfile.txt', FILE_ATTRIBUTE_HIDDEN);这行代码,会发生什么? - Tom Brunberg
显示剩余5条评论
1个回答

7

AssignFile() 并没有失败,而是您在一个设置了 Hidden 属性的文件上调用了 Rewrite()。以下是解释:

通常情况下,您会调用 Rewrite(F) 来清空文件,并使用后续的 Write(F, ...)WriteLn(F, ...) 调用写入新数据。

根据文档(System.Rewrite):

如果同名的外部文件已经存在,它将被删除并创建一个新的空文件。

使用 Append() 命令打开文件进行写入不会有问题。

(基于以上内容,我得出结论,是删除操作失败并提示“拒绝访问”信息。这是缩短过程中的一些细节。)


通过评论,我查看了代码并与 MSDN 文档进行了比较:

实际代码如下:

// if mode is fmOutput (as it is for Rewrite)
OpenMode = GENERIC_WRITE
Flags = CREATE_ALWAYS
// ...
Temp := CreateFile(t.Name, OpenMode, FILE_SHARE_READ, nil, Flags, FILE_ATTRIBUTE_NORMAL, 0);

以下是关于 IT 技术的翻译:文档

如果指定了 CREATE_ALWAYS 和 FILE_ATTRIBUTE_NORMAL,且该文件已经存在并具有 FILE_ATTRIBUTE_HIDDEN 或 FILE_ATTRIBUTE_SYSTEM 属性,则 CreateFile 失败,并将最后一个错误设置为 ERROR_ACCESS_DENIED。

对带有 hidden 属性的现有文件调用 Rewrite() 将始终失败。


这看起来有点不可信。为什么要调用DeleteFile呢?肯定应该使用适当的标志调用CreateFile。而且为什么删除隐藏文件会被阻止呢? - David Heffernan
@David 我从来没有说它调用DeleteFile,我只是重复了Rewrite文档中的内容。但是你迫使我深入跟踪,谢谢你。 - Tom Brunberg
好的,你说“如果存在,则删除,重新创建并打开进行写入。”但正如我所指出的,它并没有被删除。调用CreateFile只需要一次即可完成工作。感谢你挖掘出隐藏属性行为的文档。 - David Heffernan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接