日期:2014-05-18  浏览次数:20987 次

c#调用api(FindFirstFile,FindNextFile)高效遍历目录文件

在c#下遍历目录,应用最多的应该就是 System.IO.DirectoryInfo.GetDirectories或GetFiles了,但是当目录特别大,文件特别多时,效率不尽人意,此时我们很容易想到三个Win32API函数 FindFirstFile,FindNextFile和FindClose。这三个API搭配使用就能遍历文件和子目录了,而且可以遍历的时候随时中止,避免无谓的操作。在网上搜了一下,发现这方面的文章转载最多的应该就是http://www.cnblogs.com/xdesigner/archive/2006/12/08/586177.html  这篇了,但是按照文中描述的方法,并不能遍历子目录,没办法,就自己想办法,重新写了一个。 

以下为源代码: 

 


#region 声明WIN32API函数以及结构 **************************************
    [Serializable,
    System.Runtime.InteropServices.StructLayout
      (System.Runtime.InteropServices.LayoutKind.Sequential,
      CharSet = System.Runtime.InteropServices.CharSet.Auto
      ),
    System.Runtime.InteropServices.BestFitMapping(false)]
    private struct WIN32_FIND_DATA
    {
        public int dwFileAttributes;
        public int ftCreationTime_dwLowDateTime;
        public int ftCreationTime_dwHighDateTime;
        public int ftLastAccessTime_dwLowDateTime;
        public int ftLastAccessTime_dwHighDateTime;
        public int ftLastWriteTime_dwLowDateTime;
        public int ftLastWriteTime_dwHighDateTime;
        public int nFileSizeHigh;
        public int nFileSizeLow;
        public int dwReserved0;
        public int dwReserved1;
        [System.Runtime.InteropServices.MarshalAs
          (System.Runtime.InteropServices.UnmanagedType.ByValTStr,
          SizeConst = 260)]
        public string cFileName;
        [System.Runtime.InteropServices.MarshalAs
          (System.Runtime.InteropServices.UnmanagedType.ByValTStr,
          SizeConst = 14)]
        public string cAlternateFileName;
    }
    [System.Runtime.InteropServices.DllImport
      ("kernel32.dll",
      CharSet = System.Runtime.InteropServices.CharSet.Auto,
      SetLastError = true)]
    private static extern IntPtr FindFirstFile(string pFileName, ref WIN32_FIND_DATA pFindFileData);
    [System.Runtime.InteropServices.DllImport
      ("kernel32.dll",
      CharSet = System.Runtime.InteropServices.CharSet.Auto,
      SetLastError = true)]
    private static extern bool FindNextFile(IntPtr hndFindFile, ref WIN32_FIND_DATA lpFindFileData);
    [System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool FindClose(IntPtr hndFindFile);   
    #endregion

    //具体方法函数

     Stack<string> m_scopes = new Stack<string>();
    private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
    WIN32_FIND_DATA FindFileData;
    private System.IntPtr hFind = INVALID_HANDLE_VALUE;
    void FindFileInDir(string rootDir)
    {
        string path = rootDir;
        start:
        new FileIOPermission(FileIOPermissionAccess.PathDiscovery, Path.Combine(path, ".")).Demand();
        if (path[path.Length - 1] != '\\')
        {
            path = path + "\\";
        }
        Response.Write("文件夹为:"+path+"<br>");
        hFind = FindFirstFile(Path.Combine(path,"*"), ref FindFileData);
        if(hFind!=INVALID_HANDLE_VALUE)
        {
            do
            {
                if (FindFileData.cFileName.Equals(@".") || FindFileData.cFileName.Equals(@".."))
                    continue;
                if ((FindFileData.dwFileAttributes & 0x10) != 0)
                {
                    m_scopes.Push(Path.Combine(path, FindFileData.cFileName));
                }
                else
                {
                    Response.Write(FindFileData.cFileName+"<br>");
                }
            }
            while (FindNextFile(hFind, ref FindFileData));            
        }
        FindClose(hFind);
        if (m_scopes.Count > 0)
        {
            path = m_scopes.Pop();
            goto start;
        }
    }


//调用方法如下: 

FindFileInDir(@"D:");