.NET文件访问冲突

时间:2014-07-23 16:03:14

标签: c# .net

我觉得这有点愚蠢,但这似乎是一个真正的问题,我已经做得足够简单,以证明它不会失败。作为我工作的一部分,我负责维护在版本控制下获取文件的构建系统,并将它们复制到其他位置。听起来很简单,但在尝试复制我认为已经设置为'正常'。

的文件时,我经常遇到文件访问违规行为。

下面的代码示例只是创建一组测试文件,使它们只读,然后将它们复制到另一个文件夹。如果文件已存在于目标文件夹中,则清除RO属性,以便文件副本不会失败。

代码适用于某一点,但在看似随机的点上,尝试文件复制时会引发异常。代码都是单线程的,所以除非.NET在幕后做了导致属性设置延迟的事情,否则我无法解释问题。

如果有人能解释为什么会这样,我会感兴趣。我没有找到解决方案,除非我确实做错了,因为我已经处理过这个问题,我只是好奇,因为似乎没有其他人报告任何与此有关的事情。

经过几次迭代后,我得到了类似的东西:

类型' System.UnauthorizedAccessException'的第一次机会异常。发生在mscorlib.dll中 附加信息:访问路径' C:\ TempFolderB \ TEMPFILENAME8903.txt'被拒绝。

另一个事实是,如果在文件复制之前获得文件属性,结果状态表示文件属性确实正常,但检查本地文件会将其显示为只读。

    /// <summary>
    /// Test copying multiple files from one folder to another while resetting RO attr
    /// </summary>
    static void MultiFileCopyTest()
    {
        /// Temp folders for our test files
        string folderA = @"C:\TempFolderA";
        string folderB = @"C:\TempFolderB";

        /// Number of files to create
        const int fileCount = 10000;

        /// If the test folders do not exist populate them with some test files
        if (System.IO.Directory.Exists(folderA) == false)
        {
            const int bufferSize = 32768;

            System.IO.Directory.CreateDirectory(folderA);
            System.IO.Directory.CreateDirectory(folderB);

            byte[] tempBuffer = new byte[bufferSize];

            /// Create a bunch of files and make them all Read Only
            for (int i = 0; i < fileCount; i++)
            {
                string filename = folderA + "\\" + "TEMPFILENAME" + i.ToString() + ".txt";

                if (System.IO.File.Exists(filename) == false)
                {
                    System.IO.FileStream str = System.IO.File.Create(filename);
                    str.Write(tempBuffer, 0, bufferSize);
                    str.Close();
                }

                /// Ensure files are Read Only
                System.IO.File.SetAttributes(filename, System.IO.FileAttributes.ReadOnly);
            }
        }

        /// Number of iterations around the folders
        const int maxIterations = 100;

        for (int idx = 0; idx < maxIterations; idx++)
        {
            Console.WriteLine("Iteration {0}", idx);

            /// Loop for copying all files after resetting the RO attribute
            for (int i = 0; i < fileCount; i++)
            {
                string filenameA = folderA + "\\" + "TEMPFILENAME" + i.ToString() + ".txt";
                string filenameB = folderB + "\\" + "TEMPFILENAME" + i.ToString() + ".txt";

                try
                {

                    if (System.IO.File.Exists(filenameB) == true)
                    {
                        System.IO.File.SetAttributes(filenameB, System.IO.FileAttributes.Normal);
                    }

                    System.IO.File.Copy(filenameA, filenameB, true);
                }
                catch (System.UnauthorizedAccessException ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }
    }

3 个答案:

答案 0 :(得分:2)

(这不是一个完整的答案,但我还没有足够的声誉发表评论......)

我不认为你做错了什么,当我运行你的测试代码时我每次都可以重现这个问题。我没有经历过10次迭代而没有发生错误。

我做了进一步的测试,这可能会对这个问题有所了解:

我将TempFolderA中的所有文件设置为隐藏。

然后我确保TempFolderB中的所有文件都没有被隐藏。

我在Console.WriteLine(ex.Message)

上加了一个断点

我运行了代码,如果它超过了迭代1,那么我就停止了,重置了隐藏的属性并再次运行。

经过几次尝试后,我在第一次迭代中失败了,所以我在TempFolderB上打开了Windows资源管理器并向下滚动到有问题的文件。

文件大小为0字节,但设置了RHA属性。

不幸的是我不知道为什么会这样。 Process Monitor不会显示任何其他可能相关的活动。

答案 1 :(得分:1)

好吧,在System.IO.File.SetAttributes(string path, System.IO.FileAttributes attributes)方法的文档中,我发现了以下内容:

  

<强>例外:   System.UnauthorizedException:   
path指定了只读文件。   
- 或 - 当前平台不支持此操作。   
- 或 - 来电者没有所需的权限。

所以,如果我不得不猜测,目的地中的文件(例如filenameB)确实已经存在。它被标记为只读,因此,根据上述文档抛出异常。

相反,您需要做的是通过反位掩码删除只读属性:

if (FileExists(filenameB))
{
    // Remove the read-only attribute
    FileAttributes attributes = File.GetAttributes(filenameB);
    attributes &= ~FileAttributes.ReadOnly;
    File.SetAttributes(filenameB, attributes);

    // You can't OR the Normal attribute with other attributes--see MSDN.
    File.SetAttributes(filenameB, FileAttributes.Normal);
}

公平地说,SetAttributes方法的文档并不清楚如何在文件标记为Readonly后如何设置文件属性。当然,有一个示例(使用Hidden属性),但他们没有明确表示您需要使用反转位掩码来删除HiddenReadonly属性。人们可以很容易地认为这就是他们选择“取消设置”属性的方式。从文档中还不清楚会发生什么,例如,如果你这样标记文件:

File.SetAttributes(pathToFile, FileAttributes.Normal);
File.SetAttributes(pathToFile, FileAttributes.Archived);

这是否会导致文件首先设置Normal属性,然后 Archived,否则会导致文件设置为Normal,并且然后_adially having Archived` set,产生一个Normal,但Archived文件?我认为它是前者,而不是后者,基于如何使用反转位掩码从文件中“删除”属性。

如果有人发现任何相反的情况,请发表评论,我会相应地更新我的答案。

HTH。

答案 2 :(得分:0)

这可能会导致因为用户没有足够的权限来访问文件系统,

解决方法:

1,尝试以管理模式运行应用程序

OR

2,尝试在管理模式下运行visual studio(如果您使用的是调试器)