经过多次迭代后,删除/创建文件会引发System.UnauthorizedAccessException

时间:2019-02-05 08:15:09

标签: c# file filestream

在测试有关写入/创建/删除文件的一些东西时,我制作了以下程序,该程序可以循环n次删除和创建文件。

static string path = @"C:\Users\Remy\Desktop\Testing";
static readonly int sampleSize = 10000; // Amount of iterations the methods will be run for.

static byte[] sourceFile;

static void Main(string[] args)
{
    using (FileStream fs = new FileStream(path + @"\SourceFile.txt", FileMode.Open, FileAccess.Read))
    {
        sourceFile = new byte[fs.Length];
        fs.Read(sourceFile, 0, sourceFile.Length);
    }

    string filePath = path + @"\Destination.txt";
    for (int i = 0; i < sampleSize; i++)
    {
        if (File.Exists(filePath))
        {
            File.SetAttributes(filePath, FileAttributes.Normal);
            File.Delete(filePath);//Error sometimes throws here.
        }

        using (FileStream file = File.OpenWrite(filePath))
        {
            file.Write(sourceFile, 0, sourceFile.Length);
        }
    }

    Console.ReadLine();
}

当迭代次数不太高(大约1000次)时,该程序大部分时间都可以正常工作。它将删除旧文件并创建一个新文件。

但是,当我将迭代次数增加到10000/100000时,就会出现问题,在极少数情况下(约占0.03%的时间),它在System.UnauthorizedAccessException处抛出using (FileStream file = File.OpenWrite(filePath)),而成功地通过了其他99.97%的时间。当错误抛出该文件时,将不会创建该文件。

在使用Debug / release的VS中(以管理员身份),以及在以管理员身份运行的build.exe上都发生这种情况。

环顾此问题时,我发现了有关Unauth...异常的以下答案。

  • this的答案建议设置属性,但是如我的示例所示,我已经做到了。
  • this和其他一些答案建议以管理员权限运行该应用程序。我已经在做那条毛巾了。

我还添加了父文件夹的权限,以允许对所有文件和子文件夹的full controlEveryone

起初,我以为我正在创建的文件不够大(当前正在写入976kb的随机数据),并且由于某种原因,程序在创建/删除过程中迭代的速度比OS /硬盘处理的速度更快。但是,增加文件大小时会发生相同的行为

我已经在3台机器上进行了测试,并且都在所有机器上进行了测试。

这是否可能是Windows由于误报而引发异常的情况?看到它仅在重大事件发生时发生?我在这里错过了完全不同的东西吗?

注意:我不是在寻找一种处理异常的方法。我可以解决。我要寻找的原因为什么发生这种奇怪的行为,并且如果可能的话防止而不是治愈


环境

我要写入的磁盘是Crucial MX300 SSD,使用没有RAID的sata 3。 16 GB内存。操作系统Windows 10(pro)64位。运行程序时,系统将尽可能地空闲。

控制台应用程序使用Visual Studio 2017和Release Any CPU设置来面向.NET Framework 4.6.1构建。


我根据评论建议尝试过的其他事情:

我尝试在创建和删除后添加Thread.Sleep,以确保Windows能够清除文件缓存。仍然会引发异常,但是这次它会在File.Delete(filePath);上引发异常。

关闭Windows Defender等也会导致在File.Delete(filePath)而不是using(FIleStream....) aswel上引发错误的结果。

改为使用以下内容写入文件:

using (FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Write, FileShare.None)) 
{ 
    file.Write(sourceFile, 0, sourceFile.Length); file.Flush(flushToDisk: true); 
}

还会产生抛出相同异常的信息

1 个答案:

答案 0 :(得分:1)

没有办法可以消除此类问题,唯一的处理方法是防止或避免操作失败时记录一些日志。如果失败,请尝试多次这样的操作。以前我创建了一个,这里是代码段。

public IList<string> ReadLineByLineFromFile( string filePath )
{
    const int numberOfRetries = 3;
    const int delayOnRetry = 500;

    bool success = false;
    List<string> logs = null;

    for ( int i = 0; i <= numberOfRetries && success == false; i++ )
    {
        try
        {
            logs = new List<string>();

            const Int32 bufferSize = 128;
            using ( var fileStream = File.Open( filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite ) )
            using ( var streamReader = new StreamReader( fileStream, Encoding.UTF8, true, bufferSize ) )
            {
                string line;

                while ( ( line = streamReader.ReadLine() ) != null )
                {
                    logs.Add( line );
                }
            }

            success = true;
        }
        catch ( IOException ex ) when ( i < numberOfRetries )
        {
            Local.Instance().Logger.Warn( ex, "Retrying reading logs from file path {0}, retry count {1} with dealy {2} ms.", filePath, i + 1,
                delayOnRetry );

            System.Threading.Thread.Sleep( delayOnRetry );
        }
    }

    GC.Collect();

    return logs;
}