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中而不是继续。
答案 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();
}