繁体   English   中英

在Net 2.0中等效于EnumerateFiles()?

[英]What is the equivalent of EnumerateFiles() in Net 2.0?

我正在处理大量文件,因此,我不想等到整个搜索完成后再返回数组。 所以我不想使用Directory.GetFiles()

根据此答案 ,我需要使用EnumerateFiles()才能在搜索过程中获得结果。 但是,我使用的是NET2.0,此功能似乎是从NET 4.0开始引入的

什么是Net 2.0中的EnumerateFiles()?

任何提示将不胜感激

您需要的是WinAPI调用FindFirstFile和FindNextFile 这是一些使用包装的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);
    }
}

特别添加为新答案。

从.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的EnumerateFiles方法的棘手部分100%.net v2托管代码..

     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
            }

从.NET 2.0开始,有IENumerableyield关键字会进行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 ]
}

在此伪IENumerableyield关键字负责过滤。如果过滤返回true,则yield return立即将结果返回到IENumerable实例/被调用者。

IEnumerable负责延迟加载。

根据您的需要,也可以在循环中使用yield break关键字不包含结果。

并通过一个简单的电话:

List<string> FilesInDirectory = GetFiles( path, "*.txt").ToList();

希望这可以帮助..

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM