2
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 中而无法继续。

4

2 回答 2

4

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

如果您只想跳过您无权访问的目录(例如特殊Recycle Bin文件夹),那么您必须为 Windows API 函数FindFirstFile()FindNextFile().

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

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()FindNextFile()遍历所有文件夹和文件。上面的代码只是忽略文件,只返回文件夹。

FindFirstFileEx()使用并指定一个标志以仅返回目录会更有效。我将这种变化作为众所周知的练习留给读者。;)

于 2013-08-30T08:41:19.193 回答
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();  
}
于 2013-08-30T07:40:15.323 回答