Home > Software engineering >  How to get list of directories and files with full path using win32 in c# application
How to get list of directories and files with full path using win32 in c# application

Time:09-18

Below console application in c#.net shows only folder names in D drive without full path name but I want to have iterate recursively inside the folders , subfolder and files within those subfolders with help of win32 API because of I have to scan folders having thousands of files. Win32 API works fast so I m not using regular c#.net function for getting directories and its files.

    class Program
    {
              // Kernal32.dll import for File management operations.

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
       public static extern IntPtr FindFirstFileEx(
      string lpFileName,
      FINDEX_INFO_LEVELS fInfoLevelId,
      out WIN32_FIND_DATA lpFindFileData,
      FINDEX_SEARCH_OPS fSearchOp,
      IntPtr lpSearchFilter,
      int dwAdditionalFlags);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData);

        [DllImport("kernel32.dll")]
        static extern bool FindClose(IntPtr hFindFile);

        public const int FIND_FIRST_EX_CASE_SENSITIVE = 1;
        public const int FIND_FIRST_EX_LARGE_FETCH = 2;


        static void Main()
        {


            WIN32_FIND_DATA findData;

            FINDEX_INFO_LEVELS findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoBasic;

            int additionalFlags = 0;

            if (Environment.OSVersion.Version.Major >= 6)
            {
                findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoBasic;
                //additionalFlags = FIND_FIRST_EX_LARGE_FETCH;
            }

            string pattern = "D:\\*.*";


            IntPtr hFile = FindFirstFileEx(
            pattern,
            findInfoLevel,
            out findData,
            FINDEX_SEARCH_OPS.FindExSearchNameMatch,
            IntPtr.Zero,
            additionalFlags);

            int error = Marshal.GetLastWin32Error();

            if (hFile.ToInt32() != -1)
            {
                do
                {
                    Console.WriteLine("Found file {0}, & Attribute is {1}", findData.cFileName, findData.dwFileAttributes);
                    
                }
                while (FindNextFile(hFile, out findData));

                FindClose(hFile);


            }

            Console.ReadLine();

        }



    }

Below is required enum and struct for program.

public enum FINDEX_SEARCH_OPS
{
    FindExSearchNameMatch = 0,
    FindExSearchLimitToDirectories = 1,
    FindExSearchLimitToDevices = 2
}


public enum FINDEX_INFO_LEVELS
{
    FindExInfoStandard = 0,
    FindExInfoBasic = 1
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct WIN32_FIND_DATA
{
    public uint dwFileAttributes;
    public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
    public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
    public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
    public uint nFileSizeHigh;
    public uint nFileSizeLow;
    public uint dwReserved0;
    public uint dwReserved1;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
    public string cFileName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
    public string cAlternateFileName;

}
I have got code from Pinvoke.net and website is http://pinvoke.net/

CodePudding user response:

You can put your code into a rekursive function, and call it for each folder:

static void Main()
    {


        WIN32_FIND_DATA findData;

        FINDEX_INFO_LEVELS findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoBasic;

        int additionalFlags = 0;

        if (Environment.OSVersion.Version.Major >= 6)
        {
            findInfoLevel = FINDEX_INFO_LEVELS.FindExInfoBasic;
            //additionalFlags = FIND_FIRST_EX_LARGE_FETCH;
        }

        string startFolder = @"D:\";

        var watch = new Stopwatch();
        watch.Start();

        IterateFolder(findInfoLevel, additionalFlags, startFolder);

        watch.Stop();

        Console.WriteLine();
        Console.WriteLine($"{watch.Elapsed.TotalSeconds}");
        Console.ReadLine();

    }

public const uint FILE_ATTRIBUTE_DIRECTORY = 0x10;

    private static void IterateFolder(FINDEX_INFO_LEVELS findInfoLevel, int additionalFlags, string folder)
    {
        WIN32_FIND_DATA findData;
        IntPtr hFile = FindFirstFileEx(
                $"{folder}\\*.*",
                findInfoLevel,
                out findData,
                FINDEX_SEARCH_OPS.FindExSearchNameMatch,
                IntPtr.Zero,
                additionalFlags);

        int error = Marshal.GetLastWin32Error();

        if (hFile.ToInt32() != -1)
        {
            do
            {
                if (findData.cFileName == "." || findData.cFileName == "..") continue;//ignore folder navigation
                var foundFolder = $"{folder}\\{findData.cFileName}";
                Console.WriteLine("Found file {0}, & Attribute is {1}", foundFolder, findData.dwFileAttributes);
                if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) > 0)
                {
                    //Recursive for directories
                    IterateFolder(findInfoLevel, additionalFlags, foundFolder);
                }
            }
            while (FindNextFile(hFile, out findData));

            FindClose(hFile);


        }
        
    }
  • Related