.net 使用FileShare.Delete会导致UnauthorizedException吗?

wribegjk  于 2023-10-21  发布在  .NET
关注(0)|答案(2)|浏览(104)

我正在使用以下代码打开一个文件,该文件是我以前在用户的%TEMP%文件夹中创建的,用于阅读:

new FileStream(cacheFileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete);

在某些用户的计算机上,这有时会引发UnauthorizedException,并显示消息“Access to path.被否认”。我还没能重现这个。我最初的猜测是反病毒或索引引擎正在做一些时髦的事情,但我也注意到这段代码使用了“FileShare.Delete”,我不确定应该在那里。
是否存在使用“FileShare.Delete”导致UnauthorizedException.exe异常的情况?

5gfr0r5j

5gfr0r5j1#

是的,文件共享。删除往往会导致此问题。在后台运行的任何程序都可以使用它来扫描文件,文件索引器和病毒扫描程序就是常见的例子。
FileShare.Delete允许 * 另一个 * 进程删除文件,即使后台进程仍然打开文件并正在阅读文件。另一个进程将不会注意到文件实际上并没有消失,因为它只知道文件实际上被删除了。
当其他进程依赖于实际被删除的文件并执行其他操作时,问题就开始了。通常通过创建同名的新文件来触发。值得注意的是一个非常不明智的方式来保存文件,因为它会导致完整的数据丢失,没有备份时,保存失败,但这个错误是非常常见的。
这将失败,因为文件的目录项仍然存在,它不会消失,直到最后一个打开文件的进程关闭句柄。任何试图再次打开该文件的其他进程都将被错误5“拒绝访问”。包括删除文件并试图重新创建它的进程。
解决方法是始终使用“transactional”保存,在尝试覆盖文件之前对其进行重命名。在.NET中通过File.Replace()可用,在本机winapi中通过ReplaceFile()可用。也很容易手工完成,工作流程是:
1.删除备份文件,失败停止
1.将旧文件重命名为备份文件名,如果失败则停止
1.使用原始文件名写入新文件,如果失败则重命名备份
1.删除备份文件,忽略失败
步骤2确保永远不会有任何数据丢失,原始文件保持不变,如果出了问题。第4步确保FileShare.Delete将按预期工作,当其他进程关闭它们的句柄时,备份文件将最终消失。

qyuhtwio

qyuhtwio2#

我发现了一个场景,重现了这一点:

static void Main(string[] args)
{
    string cacheFileName = @"C:\temp.txt";
    using (var filestream = new FileStream(cacheFileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete, 4096, FileOptions.SequentialScan))
    {
        filestream.Read(new byte[100], 1, 1);
        Console.ReadLine();
        GC.KeepAlive(filestream);
    }
    Console.WriteLine("Done!");
}

创建“C:\temp.txt”文件,然后运行此程序。尝试用Explorer/TotalCommander删除文件,它不会抱怨,但也不会删除文件。然后,再次运行该程序,它将抛出UnauthorizedException。关闭两个. ex后,看起来文件最终被删除了。
删除“FileShare.Delete”可以解决这个问题,因为它不会让你在文件正在使用时尝试删除它。

相关问题