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);
}
}