我觉得这有点愚蠢,但这似乎是一个真正的问题,我已经做得足够简单,以证明它不会失败。作为我工作的一部分,我负责维护在版本控制下获取文件的构建系统,并将它们复制到其他位置。听起来很简单,但在尝试复制我认为已经设置为'正常'。
的文件时,我经常遇到文件访问违规行为。下面的代码示例只是创建一组测试文件,使它们只读,然后将它们复制到另一个文件夹。如果文件已存在于目标文件夹中,则清除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);
}
}
}
}
答案 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
属性),但他们没有明确表示您需要使用反转位掩码来删除Hidden
或Readonly
属性。人们可以很容易地认为这就是他们选择“取消设置”属性的方式。从文档中还不清楚会发生什么,例如,如果你这样标记文件:
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(如果您使用的是调试器)