你怎么能轻松地检查访问被拒绝.NET中的文件?
基本上,我想在打开之前检查一下是否有权打开文件; 除非必须,否则我不想使用try / catch来进行检查。 是否有一个文件访问属性,我可以检查之前?
过去我做过无数次,而且几乎每次做这个事情,我甚至都做错了。
文件权限(甚至文件存在)是易变的 – 他们可以在任何时候改变。 由于墨菲定律,这尤其包括你检查文件和打开文件之间的短暂时间。 如果你在一个你知道你需要首先检查的地区,那么更改更有可能。 然而奇怪的是,在您的测试或开发环境中,这种情况往往是相当静态的。 这使得以后难以追踪到这个问题,并且使这种错误很容易投入生产。
这意味着你仍然必须能够处理例外,如果文件的权限或存在是不好的,尽管你的检查。 不管是否事先检查文件的权限,都需要有异常处理代码。 异常处理代码提供了存在或权限检查的所有功能。 此外,虽然这样的异常处理程序已知很慢,但重要的是要记住,磁盘I / O更慢…慢很多 …并调用.Exists()函数或检查权限将强制额外的旅程出文件系统。
总之,在尝试打开文件之前进行初始检查是多余的和浪费的。 与异常处理相比,没有额外的好处,它实际上会损害你的性能,不会增加代码的成本,而且会增加必须维护的代码的成本,并且会在代码中引入微妙的错误。 做初步检查根本没有任何好处。 相反,这里的正确的事情是试图打开文件,如果失败,把你的努力放到一个好的异常处理程序。 即使您只是检查文件是否存在,情况也是如此。 这个推理适用于任何易失资源。
快速提示任何人来到这里与类似的问题:
注意网络同步应用程序,如DropBox。 我花了2个小时思考“使用”语句(Dispose模式)在.NET中被打破。
我终于意识到,Dropbox不断地在后台读写文件,以便同步它们。
猜猜我的Visual Studio项目文件夹的位置? 当然,在“我的Dropbox”文件夹里面。
因此,当我在Debug模式下运行我的应用程序时,它正在读取和写入的文件也不断被DropBox访问,以便与DropBox服务器同步。 这导致了锁定/访问冲突。
所以至少我现在知道我需要一个更强大的文件打开功能(即TryOpen(),将进行多次尝试)。 我很惊讶这不是框架的内置部分。
[更新]
这是我的帮手功能:
/// <summary> /// Tries to open a file, with a user defined number of attempt and Sleep delay between attempts. /// </summary> /// <param name="filePath">The full file path to be opened</param> /// <param name="fileMode">Required file mode enum value(see MSDN documentation)</param> /// <param name="fileAccess">Required file access enum value(see MSDN documentation)</param> /// <param name="fileShare">Required file share enum value(see MSDN documentation)</param> /// <param name="maximumAttempts">The total number of attempts to make (multiply by attemptWaitMS for the maximum time the function with Try opening the file)</param> /// <param name="attemptWaitMS">The delay in Milliseconds between each attempt.</param> /// <returns>A valid FileStream object for the opened file, or null if the File could not be opened after the required attempts</returns> public FileStream TryOpen(string filePath, FileMode fileMode, FileAccess fileAccess,FileShare fileShare,int maximumAttempts,int attemptWaitMS) { FileStream fs = null; int attempts = 0; // Loop allow multiple attempts while (true) { try { fs = File.Open(filePath, fileMode, fileAccess, fileShare); //If we get here, the File.Open succeeded, so break out of the loop and return the FileStream break; } catch (IOException ioEx) { // IOExcception is thrown if the file is in use by another process. // Check the numbere of attempts to ensure no infinite loop attempts++; if (attempts > maximumAttempts) { // Too many attempts,cannot Open File, break and return null fs = null; break; } else { // Sleep before making another attempt Thread.Sleep(attemptWaitMS); } } } // Reutn the filestream, may be valid or null return fs; }
Eric Lippert可能解释了为什么Joel就在这里
首先,Joel Coehoorn说。
另外:你应该检查的假设,你的愿望,避免使用try / catch,除非你必须。 避免依赖异常的逻辑(创建Exception
对象执行效果不佳)的典型原因可能与打开文件的代码无关。
我想如果你正在编写一个方法,通过打开目录子树中的每个文件来填充一个List<FileStream>
,并且你期望它们中的大量文件是不可访问的,你可能想要在打开一个文件之前检查文件权限,这样你没有得到太多的例外。 但是你仍然会处理这个异常。 另外,如果你正在编写一个这样的方法,那么你的程序的设计可能会有很大的错误。
这是您正在寻找的解决方案
var fileIOPermission = new FileIOPermission(FileIOPermissionAccess.Read, System.Security.AccessControl.AccessControlActions.View, MyPath); if (fileIOPermission.AllFiles == FileIOPermissionAccess.Read) { // Do your thing here... }
这为所有文件的路径创建了基于视图的读取新权限,然后检查它是否等于文件访问读取。
public static FileStream GetFileStream(String filePath, FileMode fileMode, FileAccess fileAccess, FileShare fileShare, ref int attempts, int attemptWaitInMilliseconds) { try { return File.Open(filePath, fileMode, fileAccess, fileShare); } catch (UnauthorizedAccessException unauthorizedAccessException) { if (attempts <= 0) { throw unauthorizedAccessException; } else { Thread.Sleep(attemptWaitInMilliseconds); attempts--; return GetFileStream(filePath, fileMode, fileAccess, fileShare, ref attempts, attemptWaitInMilliseconds); } } }