2014-05-12 72 views
0

我正在處理大量文件,因此,我不想等到整個搜索完成之後再返回數組。所以我不希望使用Directory.GetFiles()Net 2.0中EnumerateFiles()的等效功能是什麼?

this answer,我需要使用EnumerateFiles(),以便在搜索過程中,得到的結果。但是,我使用的是NET2.0,並且這個功能似乎是從NET 4.0開始引入的。

Net 2.0中EnumerateFiles()的等效值是多少?

任何提示將高度讚賞

+0

沒有等效。但是,如果處理過程複雜且昂貴,則「Directory.GetFiles」是錯誤的地方。您可以優化處理方法,或者可以使用'GetFiles'加載所有路徑,然後一個接一個地處理,例如每隔10個文件。 –

+0

你認爲這個答案是我需要http://stackoverflow.com/a/929418/2340370? –

+2

即使迭代器一個接一個地輸出,它仍然會先使用'Directory.GetFiles(path)'。所以不行,這只是假定延遲執行一個包含大量文件的單個目錄。 –

回答

-2

由於.NET 2.0有IENumerableyield關鍵字做Lazy Initialization ..With這些,你可以得到你想要的。

與僞:

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關鍵字採取filtering..If過濾的責任返回true yield return立即將結果返回給IENumerable實例/被叫..

IEnumerable負責延遲加載..

取決於您的需求,也可以使用yield break關鍵字在循環中不包括inc路得的結果..

並配有簡單的電話:

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

希望這有助於..

+0

。 。 。你從哪裏得到實際的文件名? –

+0

@BinaryWorrier如果Op想要的話,在for循環中可以有一個FileInfo..Or,因爲Op需要,在獲得結果後,使用另一個循環/線程列出結果,他可以獲取文件名..當我們知道yield關鍵字返回立即..所以,不需要等待整個數組/列表執行;) – sihirbazzz

+0

不,對不起,我不能跟着,你可以添加一些實際的代碼,顯示你會得到的文件名? –

1

你需要的是WinAPI的要求FindFirstFile and 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); 
    } 
} 
+0

這不會打破不包含任何文件的目錄嗎?您返回一個文件名而不檢查「FindFirstFile」是否成功, – CodesInChaos

+0

只是發現並修復了它。就像我說的那樣,將EnumerateFiles視爲僞代碼。感謝您的反饋。 –

+0

反對,沒有解釋,這怎麼可能?如果我的答案有問題,你可以告訴我它是什麼嗎?畢竟我們都在這裏學習:) –

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過濾,所以你不會得到內存問題,這取決於你的fi les count ..這是試圖模仿.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 
      } 
相關問題