我正在处理大量文件,因此,我不想等到整个搜索完成后再返回数组。所以我不想使用 Directory.GetFiles()
根据this answer,我需要使用EnumerateFiles()以便在搜索过程中获得结果。但是,我使用的是NET2.0,这个功能似乎是从.NET 4.0开始引入的。
Net 2.0中EnumerateFiles()的等价物是什么?
任何提示都将受到高度赞赏
答案 0 :(得分:1)
您需要的是FindFirstFile and FindNextFile的WinAPI调用。 这是一些使用包装的api调用的代码。
IEnumerable<string> EnumerateFiles(string path)
{
APIWrapper.FindData findData = new APIWrapper.FindData();
APIWrapper.SafeFindHandle handle = APIWrapper.SafeNativeMethods.FindFirstFile(System.IO.Path.Combine(path, "*"), findData);
if(!handle.IsInvalid && !handle.IsClosed)
{
yield return findData.fileName;
while(!APIWrapper.SafeNativeMethods.FindNextFile(handle, findData))
yield return findData.fileName;
handle.Close();
}
}
我只需要输入EnumerateFiles
,所以将其视为伪代码,但它所依赖的类是生产就绪,这就是它在这里
internal class APIWrapper
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal sealed class FILETIME
{
public int Low;
public int High;
public Int64 ToInt64()
{
Int64 h = High;
h = h << 32;
return h + Low;
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal sealed class FindData
{
public int fileAttributes;
public FILETIME CreationTime;
public FILETIME LastAccessTime;
public FILETIME LastWriteTime;
public int FileSizeHigh;
public int FileSizeLow;
public int dwReserved0;
public int dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public String fileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public String alternateFileName;
}
internal sealed class SafeFindHandle : Microsoft.Win32.SafeHandles.SafeHandleMinusOneIsInvalid
{
/// <summary>
/// Constructor
/// </summary>
public SafeFindHandle()
: base(true)
{
}
/// <summary>
/// Release the find handle
/// </summary>
/// <returns>true if the handle was released</returns>
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
protected override bool ReleaseHandle()
{
return SafeNativeMethods.FindClose(handle);
}
}
internal enum SearchOptions
{
NameMatch,
LimitToDirectories,
LimitToDevices
}
[SecurityPermissionAttribute(SecurityAction.Assert, UnmanagedCode = true)]
internal static class SafeNativeMethods
{
[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
public static extern SafeFindHandle FindFirstFile(String fileName, [In, Out] FindData findFileData);
[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
public static extern SafeFindHandle FindFirstFileEx(
String fileName, //__in LPCTSTR lpFileName,
[In] int infoLevel, //__in FINDEX_INFO_LEVELS fInfoLevelId,
[In, Out] FindData findFileData, //__out LPVOID lpFindFileData,
[In, Out] SearchOptions SerchOps, //__in FINDEX_SEARCH_OPS fSearchOp,
[In] int SearchFilter, //__reserved LPVOID lpSearchFilter,
[In] int AdditionalFlags); //__in DWORD dwAdditionalFlags
[DllImport("kernel32", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FindNextFile(SafeFindHandle hFindFile, [In, Out] FindData lpFindFileData);
[DllImport("kernel32", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FindClose(IntPtr hFindFile);
}
}
答案 1 :(得分:0)
特别添加为新答案..
从.NET 2.0开始,有IENumerable和yield关键字执行延迟初始化/延迟执行。有了这些,你可以得到你想要的。
public IEnumerable<string> GetFiles(string rootPath, string [] fileNameStartChars, string[] extensionsFilter)
{
FileSystemInfo[] fsi = null;
for(int i = 0; i < fileNameStartChars.Length; i++)
{
for(int k = 0; k<extensionsFilter.Length; k++)
{
fsi = new DirectoryInfo(rootPath).GetFileSystemInfos(fileNameStartChars[i]+extensionsFilter[k]);
if (fsi.Length > 0)
{
for (int j = 0; j < fsi.Length; j++)
{
/// .Name returns the filename with extension..if you need, please implement here a substring for eliminate the extension of the file
yield return fsi[j].Name;
}
}
}
}
}
用法:
可能的文件名startsWithChar表
public string[] table = new string[]
{
"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z",
"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",
"1","2","3","4","5","6","7","8","9","0","#","_","-",".","@","+",",","%","&","(",")","[","]","{","}","*",
"<",">","^"," ","|",";","`"
};
扩展名:
string[] Exts = new string[] { ".mp3", ".midi", ".wav"};
使用此方法,您可以在小部件中过滤数据,例如使用startswithchar过滤,这样您就不会遇到依赖于文件计数的内存问题。这是尝试模仿.net v4的棘手部分具有100%.net v2托管代码的EnumerateFiles方法..
IEnumerable<string> strNumerable = GetFiles(@"D:\Music", table, Exts);
///Since its deferred execution, method didn't get any memory alloc for your data till now..Memory Alloc will start within this foreach..
foreach (string s in strNumerable)
{
//do your work
}
答案 2 :(得分:-2)
自.NET 2.0以来IENumerable
和yield
关键字Lazy Initialization
已完成。有了这些,您就可以满足自己的需求。
使用伪:
public IENumerable GetFiles(string Path, string FileExtension)
{
// Create a new IENumerable instance
// Get FileCount with DirectoryInfo or some similar
// Implement a for-loop with File count
// If DirectoryFiles [ indexOfForLoop ] .Extension == FileExtension
yield return DirectoryFiles [indexOfForLoop ]
}
在这个伪中,yield
关键字负责过滤。如果过滤返回true,yield return
会立即将结果返回给IENumerable
实例/被调用者。
IEnumerable
负责延迟加载..
取决于您的需求,您也可以在循环中使用yield break
关键字来包含结果..
通过一个简单的电话:
List<string> FilesInDirectory = GetFiles( path, "*.txt").ToList();
希望这会有所帮助..