How can I perform full recursive directory & file scan? - c#

here is my code:
private static void TreeScan(string sDir)
{
foreach (string d in Directory.GetDirectories(sDir))
{
foreach (string f in Directory.GetFiles(d))
{
//Save file f
}
}
TreeScan(d, client);
}
The problem is that it doesn't get the FILES of the sDir (Starting Directory) it only gets the Folders and the Files in the Sub Folders.
How can I make it get the files from the sDir too ?

Don't reinvent the wheel, use the overload of GetFiles that allows you to specify that it searches subdirectories.
string[] files
= Directory.GetFiles(path, searchPattern, SearchOption.AllDirectories);

private static void TreeScan( string sDir )
{
foreach (string f in Directory.GetFiles( sDir ))
{
//Save f :)
}
foreach (string d in Directory.GetDirectories( sDir ))
{
TreeScan( d );
}
}

There are some problems with your code. For one, the reason you never saw the files from the root folder is because your recursed before doing and file reads. Try this:
public static void Main()
{
TreeScan(#"C:\someFolder");
}
private static void TreeScan(string sDir)
{
foreach (string f in Directory.GetFiles(sDir))
Console.WriteLine("File: " + f); // or some other file processing
foreach (string d in Directory.GetDirectories(sDir))
TreeScan(d); // recursive call to get files of directory
}

You have to use
Directory.GetFiles(targetDirectory);
like in This sample, wich contains a complete implementation of what you're looking for

Your GetFiles loop should be outside the GetDirectories loop. And shouldn't your TreeScan stay inside GetDirectories loop? In short the code should look like this:
private static void TreeScan(string sDir)
{
foreach (string d in Directory.GetDirectories(sDir))
{
TreeScan(d, client);
}
foreach (string f in Directory.GetFiles(d))
{
//Save file f
}
}

If using Fx4 and above the EnumerateFiles method will return all files with efficient memory management, whereas GetFiles can require max resources on big directories (or drives).
var files = Directory.EnumerateFiles(dir.Path, "*.*");

Related

How to write list<String> to a text file?

How can append f to a list each time, then write the list into a text file ? I tried with the following code but the text file is always empty?
static void DirSearch(string dir, string pattern)
{
try
{
List<String> filesList = new List<string>();
foreach (string f in Directory.GetFiles(dir, pattern))
//Console.WriteLine(f);
{
// Console.WriteLine(f); // // <- This works correctly
filesList.Add(f);
}
foreach (string d in Directory.GetDirectories(dir))
{
//Console.WriteLine(d);
DirSearch(d, pattern);
}
File.WriteAllLines("files.txt", filesList.ToArray());
}
catch (System.Exception ex)
{
//Console.WriteLine(ex.Message);
}
}
I suspect the problem is that on each invocation of DirSearch, you're overwriting the file output from previous invocations. If the final invocation has no files (only directories) you'll end up with an empty file.
Options:
Use Directory.GetFiles(dir, pattern, SearchOption.AllDirectories so you don't need to use recursion at all.
Use File.AppendAllLines instead of File.WriteAllLines
Build up the list entirely in memory (recursively) and only at the very end call File.WriteAllLines.
The latter approach would look something like this:
public static DirSearch(string dir, string pattern)
{
List<string> files = new List<string>();
DirSearchImpl(dir, pattern, files);
File.WriteAllLines("files.txt", files);
}
private static DirSearchImpl(string dir, string pattern, List<string> files)
{
// Simpler than your previous loop...
files.AddRange(Directory.GetFiles(dir, pattern));
foreach (var subdirectory in Directory.GetDirectories(dir))
{
DirSearchImpl(subdirectory, pattern, files);
}
}
I'd also suggest changing your exception handling - catching Exception is rarely a good idea, and I'm not sure you really want to keep going if things fail, do you?

Crawling a directory

I have this test path:
private static string dCrawler = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "TestLetters";
Is there a way to say:
foreach (item in dCrawler)
{
if (item.isFile)
{
// check file info date modified code
} else
{
foreach (fileinfo file in ...
}
}
so far I have only found ways to check a file in a directory. Is the only way to do it by having two separate loops one for files and one for folders?
You can use Directory.GetFiles(); that returns a string[] and use the string value to create your FileInfo. Like this
foreach (string n in Directory.GetFiles(dCrawler))
{
FileInfo b = new FileInfo(n);
}
To get directories, you can similarly use Directory.GetDirectories();
foreach (string n in Directory.GetDirectories(dCrawler))
{
DirectoryInfo b = new DirectoryInfo(n);
}

Is it possible to speed this recursive directory method up?

I am listing all directories in a console app, but it takes forever, more than 10+ minutes (just assuming here, it probably took more than 10 minutes), I know there are a ton of directories, but is 10+ minutes too long to begin with?
class Program
{
static void Main(string[] args)
{
DirSearch(#"c:\");
Console.ReadKey();
}
static void DirSearch(string sDir)
{
try
{
foreach (string d in Directory.GetDirectories(sDir))
{
Console.WriteLine(d);
DirSearch(d);
}
}
catch (System.Exception excpt)
{
Console.WriteLine(excpt.Message);
}
}
}
Yes - don't make it recursive manually. This is built in, you can use SearchOption.AllDirectories to include all subdirectories in your search:
foreach (string d in Directory.GetDirectories(sDir, "*.*", SearchOption.AllDirectories))
{
Console.WriteLine(d);
}
Or alternatively use Directory.EnumerateDirectories which yields directory names as it finds them instead of putting all of them in an array first:
foreach (string d in Directory.EnumerateDirectories(sDir, "*.*", SearchOption.AllDirectories))
{
Console.WriteLine(d);
}

list recursively all files and folders under the given path? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to recursively list all the files in a directory in C#?
I want to list the "sub-path" of files and folders for the giving folder (path)
let's say I have the folder C:\files\folder1\subfolder1\file.txt
if I give the function c:\files\folder1\
I will get
subfolder1
subfolder1\file.txt
You can use the Directory.GetFiles method to list all files in a folder:
string[] files = Directory.GetFiles(#"c:\files\folder1\",
"*.*",
SearchOption.AllDirectories);
foreach (var file in files)
{
Console.WriteLine(file);
}
Note that the SearchOption parameter can be used to control whether the search is recursive (SearchOption.AllDirectories) or not (SearchOption.TopDirectoryOnly).
Try something like this:
static void Main(string[] args)
{
DirSearch(#"c:\temp");
Console.ReadKey();
}
static void DirSearch(string dir)
{
try
{
foreach (string f in Directory.GetFiles(dir))
Console.WriteLine(f);
foreach (string d in Directory.GetDirectories(dir))
{
Console.WriteLine(d);
DirSearch(d);
}
}
catch (System.Exception ex)
{
Console.WriteLine(ex.Message);
}
}
String[] subDirectories;
String[] subFiles;
subDirectories = System.IO.Directory.GetDirectories("your path here");
subFiles = System.IO.Directory.GetFiles("your path here");
Use the System.IO.Directory class and its methods
I remember solving a similar problem not too long ago on SO, albeit it was in VB. Here's the question.

Solving UnauthorizedAccessException issue for listing files

Listing all files in a drive other than my system drive throws an UnauthorizedAccessException.
How can I solve this problem?
Is there a way to grant my application the access it needs?
My code:
Directory.GetFiles("S:\\", ...)
Here's a class that will work:
public static class FileDirectorySearcher
{
public static IEnumerable<string> Search(string searchPath, string searchPattern)
{
IEnumerable<string> files = GetFileSystemEntries(searchPath, searchPattern);
foreach (string file in files)
{
yield return file;
}
IEnumerable<string> directories = GetDirectories(searchPath);
foreach (string directory in directories)
{
files = Search(directory, searchPattern);
foreach (string file in files)
{
yield return file;
}
}
}
private static IEnumerable<string> GetDirectories(string directory)
{
IEnumerable<string> subDirectories = null;
try
{
subDirectories = Directory.EnumerateDirectories(directory, "*.*", SearchOption.TopDirectoryOnly);
}
catch (UnauthorizedAccessException)
{
}
if (subDirectories != null)
{
foreach (string subDirectory in subDirectories)
{
yield return subDirectory;
}
}
}
private static IEnumerable<string> GetFileSystemEntries(string directory, string searchPattern)
{
IEnumerable<string> files = null;
try
{
files = Directory.EnumerateFileSystemEntries(directory, searchPattern, SearchOption.TopDirectoryOnly);
}
catch (UnauthorizedAccessException)
{
}
if (files != null)
{
foreach (string file in files)
{
yield return file;
}
}
}
}
You can the use it like this:
IEnumerable<string> filesOrDirectories = FileDirectorySearcher.Search(#"C:\", "*.txt");
foreach (string fileOrDirectory in filesOrDirectories)
{
// Do something here.
}
It's recursive, but the use of yield gives it a low memory footprint (under 10KB in my testing). If you want only files that match the pattern and not directories as well just replace EnumerateFileSystemEntries with EnumerateFiles.
Are you allowed to access the drive? Can the program access the drive when it's not run from Visual Studio? Are restrictive permissions defined in the project's Security page ("Security Page, Project Designer")?
In .net core you can do something like this below. It can search for all subdirectories recursively with good performance and ignoring paths without access.
I also tried other methods found in
How to quickly check if folder is empty (.NET)? and
Is there a faster way than this to find all the files in a directory and all sub directories? and
https://www.codeproject.com/Articles/1383832/System-IO-Directory-Alternative-using-WinAPI
public static IEnumerable<string> ListFiles(string baseDir)
{
EnumerationOptions opt = new EnumerationOptions();
opt.RecurseSubdirectories = true;
opt.ReturnSpecialDirectories = false;
//opt.AttributesToSkip = FileAttributes.Hidden | FileAttributes.System;
opt.AttributesToSkip = 0;
opt.IgnoreInaccessible = true;
var tmp = Directory.EnumerateFileSystemEntries(baseDir, "*", opt);
return tmp;
}
I solved the problem. Not really but at least the source.
It was the SearchOption.AllDirectories option that caused the exception.
But when I just list the immediate files using Directories.GetFiles, it works.
This is good enough for me.
Any way to solve the recursive listing problem?

Categories

Resources