获取所有目录并捕获权限异常并继续

时间:2013-08-30 07:21:27

标签: c#

public void newestFile(string path)
{
    try
    {
        foreach (var item in dir.GetDirectories("*.*", SearchOption.AllDirectories))
        {
            var file = item.GetFiles().OrderByDescending(f => f.LastWriteTime).First();
        } 
    }
    catch (Exception ex)
    {

    }                     
}

我想从特定路径的每个目录中获取最新文件,并在捕获权限异常后继续,目前我的代码卡在catch中而不是继续。

2 个答案:

答案 0 :(得分:4)

不幸的是,Microsoft的GetDirectories()实现非常糟糕,并且不处理与访问权限相关的IO异常。

如果您只想跳过您无权访问的目录(例如特殊的Recycle Bin文件夹),那么您必须为Windows API函数编写自己的包装器{{ 1}}和FindFirstFile()

这是一个完整的例子。如果你运行它,你会看到它列出了所有 C:驱动器上的可访问目录。

FindNextFile()

注意:此代码使用using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Security.Permissions; using Microsoft.Win32.SafeHandles; namespace Demo { public class Program { private void run() { string root = "C:\\"; foreach (var folder in FolderEnumerator.EnumerateFoldersRecursively(root)) Console.WriteLine(folder); } private static void Main() { new Program().run(); } } public static class FolderEnumerator { public static IEnumerable<string> EnumerateFoldersRecursively(string root) { foreach (var folder in EnumerateFolders(root)) { yield return folder; foreach (var subfolder in EnumerateFoldersRecursively(folder)) yield return subfolder; } } public static IEnumerable<string> EnumerateFolders(string root) { WIN32_FIND_DATA findData; string spec = Path.Combine(root, "*"); using (SafeFindHandle findHandle = FindFirstFile(spec, out findData)) { if (!findHandle.IsInvalid) { do { if ((findData.cFileName != ".") && (findData.cFileName != "..")) // Ignore special "." and ".." folders. { if ((findData.dwFileAttributes & FileAttributes.Directory) != 0) { yield return Path.Combine(root, findData.cFileName); } } } while (FindNextFile(findHandle, out findData)); } } } internal sealed class SafeFindHandle: SafeHandleZeroOrMinusOneIsInvalid { [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] public SafeFindHandle(): base(true) { } protected override bool ReleaseHandle() { if (!IsInvalid && !IsClosed) { return FindClose(this); } return (IsInvalid || IsClosed); } protected override void Dispose(bool disposing) { if (!IsInvalid && !IsClosed) { FindClose(this); } base.Dispose(disposing); } } [StructLayout(LayoutKind.Sequential)] internal struct FILETIME { public uint dwLowDateTime; public uint dwHighDateTime; public long ToLong() { return dwLowDateTime + ((long)dwHighDateTime) << 32; } }; [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] internal struct WIN32_FIND_DATA { public FileAttributes dwFileAttributes; public FILETIME ftCreationTime; public FILETIME ftLastAccessTime; public FILETIME ftLastWriteTime; public int nFileSizeHigh; public int nFileSizeLow; public int dwReserved0; public int dwReserved1; [MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_PATH)] public string cFileName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_ALTERNATE)] public string cAlternate; } [DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)] private static extern SafeFindHandle FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData); [DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool FindNextFile(SafeHandle hFindFile, out WIN32_FIND_DATA lpFindFileData); [DllImport("kernel32.dll", SetLastError=true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool FindClose(SafeHandle hFindFile); private const int MAX_PATH = 260; private const int MAX_ALTERNATE = 14; } } FindFirstFile()来迭代所有文件夹AND文件。上面的代码只是忽略文件而只返回文件夹。

使用FindFirstFileEx()并指定一个仅返回目录的标志会更有效。我把这种变化作为读者的谚语。 ;)

答案 1 :(得分:0)

public string[] newestFile(string path){    
    IEnumerable<string> files = new string[]{};
    foreach (var item in dir.GetDirectories(Path.Combine(path,"*.*"), SearchOption.AllDirectories))
    {
       try {
        files = files.Concat(item.GetFiles().OrderByDescending(f => f.LastWriteTime).First());
       }
       catch {}
    }   
    return files.ToArray();  
}