Searching through a file structure to count items in a subfolder - c#

I am having an issue with trying to make a list by searching through a file structure. Was trying to make a basic c# console program that would just run and do this.
My structure is organize like the following.
My Network \
X1 \
Users \
(many many user folders) \
Search for a specific sub folder \
make a list in a text file of any folders within this sub folder
So i have to be able to search every user folder and then check for a folder (this will be the same every time) Then make a list of the found folders within that sub folder with the following format
username (name of the user folder) >> Name of folder within the specific folder.
its been a terribly long time since i have had to try anything with searching within a file structure so blanking on this terribly.
**************** EDIT!!!!!
Thanks for the info and links. Working on this now but wondering if this makes sense and would work. Don't want to just test it before i make sure it looks like something that wouldn't just screw up.
TextWriter outputText = new StreamWriter(#"C:\FileList.txt", true);
outputText.WriteLine("Starting scan through user folder");
string path = #"\\X1\users";
string subFolder = "^^ DO NOT USE - MY DOCS - BACKUP ^^";
string [] user_folders = Directory.GetDirectories(path);
foreach (var folder in user_folders)
{
string checkDirectory = folder + "\\" + subFolder;
if (Directory.Exists(checkDirectory) == true)
{
string [] inner_folders = Directory.GetDirectories(checkDirectory);
foreach (var folder2 in inner_folders)
{
outputText.WriteLine(folder2);
}
}
}
outputText.WriteLine("Finishing scan through user folder");
outputText.Close();
Fixed and working!!!! had to change the string [] lines, to make it .GetDirectories instead of .GetFiles!!

As Bali C mentioned, the Directory class will be your friend on this one. The following examples should get you started.
From: http://social.msdn.microsoft.com/Forums/en-US/Vsexpressvcs/thread/3ea19b83-b831-4f30-9377-bc1588b94d23/
//Obviously you'll need to define the correct path.
string path = #"My Network\X1\Users\(many many user folders)\Search for a specific sub folder \";
// Will Retrieve count of all files in directry and sub directries
int fileCount = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories).Length;
// Will Retrieve count of all files in directry but not sub directries
int fileCount = Directory.GetFiles(path, "*.*", SearchOption.TopDirectory).Length;
// Will Retrieve count of files .txt extensions in directry and sub directries
int fileCount = Directory.GetFiles(path, "*.txt", SearchOption.AllDirectories).Length;
If you need to search the /Users/ folder for certain people, or certain conditions you could do the following:
string path = #"PATH_TO_USERS_DIRECTORY";
string [] user_folders = Directory.GetFiles(path);
foreach(var folder in user_folders)
{
if folder == "MyFolder";
Process(folder); //Search the directory here.
}

Try the following implementation. This will just write to the console:
const string root = "<<your root path>>";
const string directoryToLookFor = "<<the folder name you are looking for>>";
foreach (var directory in Directory.EnumerateDirectories(root, "*.*", SearchOption.TopDirectoryOnly))
{
var foundDirectory = Directory.EnumerateDirectories(directory, directoryToLookFor, SearchOption.TopDirectoryOnly).FirstOrDefault();
if (!String.IsNullOrEmpty(foundDirectory))
{
var filesInside = Directory.GetFiles(foundDirectory);
foreach (var file in filesInside)
{
Console.WriteLine(file);
}
}
}
Or you could just do:
foreach (var foundDirectory in Directory.EnumerateDirectories(root, directoryToLookFor, SearchOption.AllDirectories))
{
var filesInside = Directory.GetFiles(foundDirectory);
foreach (var file in filesInside)
{
Console.WriteLine(file);
}
}
Which would search within all subdirectories without you having to iterate over the users' folders.

Related

How to make program read every folder inside the directory and every file inside each folder

I am trying to create a program that reads the folders inside the main directory and for each folder read each file (PDF) then move on to the next folder.
The code below is where i declare strings and start with a foreach statement.
string input_Path = #"C:\Users\username\Desktop\testinp\";
string output_Path = #"C:\Users\username\Desktop\testinp\output\";
string[] dirs = Directory.GetDirectories(input_Path, "*", SearchOption.TopDirectoryOnly);
string[] files = Directory.GetFiles(input_Path, "*.pdf");
foreach (string dir in dirs)
{
string dirName = dir;
}
Here is a complete explanation of how to do it along with code examples. https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/file-system/how-to-iterate-through-a-directory-tree

Accessing files within child directories

I am trying to access the files in the images directory that lies within another directory but when I run my code it doesn't print out anything:
string path = #"C:\Path";
DirectoryInfo DFolder = new DirectoryInfo(path);
Collection cDetails = new Collection(DFolder);
string DFPath = DFolder.Name;
DirectoryInfo imDetails = new DirectoryInfo(imPath);
// Get Desired Directories
List<string> directoryFilter = new List<string> {"images", "videos", "RAW"};
List<DirectoryInfo> directoryList = DFolder
.GetDirectories("*", SearchOption.AllDirectories)
.Where(x => directoryFilter.Contains(x.Name.ToLower()))
.ToList();
string dpath = directoryList.ToString();
foreach (DirectoryInfo record in directoryList)
{
foreach (FileInfo file in record.GetFiles(#"*", SearchOption.TopDirectoryOnly))
{
Console.WriteLine(file); //It compiles but doesn't print anything on the console
}
}
Note: This isn't really an answer, so I'll delete it shortly, but wanted to give some sample code to test with in case it helps.
Your code works fine for me, so it seems that the problem is that either the directories don't exist, or they don't contain any files.
Here's a test program you can run which creates a bunch of directories under c:\temp, some of which have the names we care about. The names we care about are also found at different levels of depth in the path, yet they are all discovered:
static void CreateTestPathsAndFiles()
{
// Paths to create for testing. We will put a file in each directory below,
// but our search code should only print the file paths of those files that
// are directly contained in one of our specially-named folders
var testPaths = new List<string>
{
#"c:\temp\dummy1",
#"c:\temp\dummy1\raw", // This should print
#"c:\temp\dummy2",
#"c:\temp\dummy2\extra",
#"c:\temp\dummy3",
#"c:\temp\dummy3\dummy31",
#"c:\temp\dummy3\dummy32\raw", // This should print
#"c:\temp\extra",
#"c:\temp\images", // This should print
#"c:\temp\notUsed",
#"c:\temp\notUsed\videos", // This should print
#"c:\temp\raw", // This should print
#"c:\temp\videos\dummy1",
};
// Just something to make a unique file name
int fileId = 0;
// for testing, ensure that the directories exist and contain some files
foreach(var testPath in testPaths)
{
// Create the directory
Directory.CreateDirectory(testPath);
// Add a file to it
File.CreateText(Path.Combine(testPath, $"TempFile{fileId}.txt"))
.Write($"Dummy text in file {fileId}");
// Increment our file counter
fileId++;
}
}
static void Main(string[] args)
{
// Create our paths and files for testing
CreateTestPathsAndFiles();
// Now set our root directory, search for all folders matching our
// special folder names, and print out the files contained in them
var path = #"C:\Temp";
var directoryFilter = new List<string> {"images", "videos", "raw"};
// Get ALL sub-directories under 'path' whose name is in directoryFilter
var subDirectories = new DirectoryInfo(path)
.GetDirectories("*", SearchOption.AllDirectories)
.Where(x => directoryFilter.Contains(x.Name.ToLower()));
foreach (DirectoryInfo subDir in subDirectories)
{
foreach (FileInfo file in subDir.GetFiles(#"*", SearchOption.TopDirectoryOnly))
{
// We're using the FullName so we see the whole file path in the output
Console.WriteLine(file.FullName);
}
}
GetKeyFromUser("\nDone! Press any key to exit...");
}
Output
Note that the 5 files we expected to find are listed, but no others:
foreach (FileInfo file in record.GetFiles(#"*", SearchOption.TopDirectoryOnly))
{
Console.WriteLine(file); //It compiles but doesn't print anything on the console
}
SearchOption.TopDirectoryOnly will only search files in C://Path/images but not its subfolders.
a possible fix for this is to simply change your 2nd foreach loop to look like this:
foreach (FileInfo file in record.GetFiles(#"*", SearchOption.AllDirectories))
{
Console.WriteLine(file); //It compiles but doesn't print anything on the console
}
Edit:
Using SearchOption.AllDirectories as parameter is supposed to catch all cases of subfolders within your subfolder e.g. something like C://images//dir//somefile.txt instead of only taking the files within the topdirectory(in this case C://images). Which is(as i understood your question) exactly the kind of behaviour you were looking for.
Full code:
{
static void Main(string[] args)
{
// Directory Info
string path = #"C:\Path";
DirectoryInfo DFolder = new DirectoryInfo(path);
string DFPath = DFolder.Name;
// Get Desired Directories
List<string> directoryFilter = new List<string> { "images", "videos", "raw" };
List<DirectoryInfo> directoryList = DFolder.GetDirectories("*", SearchOption.AllDirectories).Where(x => directoryFilter.Contains(x.Name.ToLower())).ToList();
string dpath = directoryList.ToString();
foreach (DirectoryInfo record in directoryList)
{
foreach (FileInfo file in record.GetFiles(#"*", SearchOption.AllDirectories)) //searches directory record and its subdirectories
{
Console.WriteLine(file);
}
}
}
Final Edit: Sample output given the following structure:
C://Path//images//images.somefile.txt
C://Path//images//temp//images.temp.somefile.txt
C://Path//raw//raw.somefile.txt
C://Path//vidoes//videos.somefile.txt

C# How to loop through the source folder or subfolders that match the destination

I need to overwrite files from a source to a destination directory.
The structure of each folder is different so i'm trying to do it in a generic way.
The thing is, each folder (source and destination) could have numerous subdirectories or none at all.
The code I currently have is this:
//copy and overwrite the files depending on whatever is in the destination
//search through the destination to find the file
foreach (var dstfile in Directory.GetFiles(targetDir))
{
//search through the source to find the matching file
foreach (var srcfile in Directory.GetFiles(sourceDir))
{
//cut off the source file from the source path
strSrcFile = srcfile.Split(Path.DirectorySeparatorChar).Last();
strDstFile = dstfile.Split(Path.DirectorySeparatorChar).Last();
//if the destination and source files match up, replace the desination with the source
if (strSrcFile == strDstFile)
{
File.Copy(srcfile, Path.Combine(targetDir, Path.GetFileName(strSrcFile)), true);
}
}
}
//look through the subfolders to see if any files match up
foreach (var srcFolder in Directory.GetDirectories(sourceDir))
{
//search through the source for the files
foreach (var srcFile in Directory.GetFiles(srcFolder))
{
//search through the destination for the files
foreach (var dstFile in Directory.GetFiles(targetDir))
{
As you can see there are a lot of foreach loops, is there a way to streamline this?
Make a hash (dictionary) of the destination directory, then walk the source directory and see if the files already exist.
Dictionary<string,string> lut1 = new Dictionary<string,string>();
foreach (var dstfile in Directory.GetFiles(targetDir))
{
strDstFile = dstfile.Split(Path.DirectorySeparatorChar).Last();
lut1 [strDstFile ] = dstfile;
}
foreach (var srcfile in Directory.GetFiles(sourceDir))
{
strSrcFile = srcfile.Split(Path.DirectorySeparatorChar).Last();
string dstfile;
if (lut1.TryGetValue(strSrcFile, out dstfile)) {
File.Copy( srcfile,dstfile,true);
}
}
I haven't tested this but this should work (Not 100% efficient), Should give you some pointers at least
public void UpdateFiles(string directory, string otherDir)
{
var dirFiles = Directory.EnumerateFiles(directory, "*",
SearchOption.AllDirectories);
var otherDirFiles = Directory.EnumerateFiles(otherDir, "*",
SearchOption.AllDirectories);
foreach (var file in dirFiles)
{
string fi = Path.GetFileName(file);
var newFile = otherDirFiles.Where(x => fi == Path.GetFileName(x));
foreach(var foundFile in newFile)
File.Copy(file , foundFile, true);
}
}
I just did it this way in a console app... tested it to work for main target folder and sub folders, although probably not the most efficient.
Call this:
OperateOnSourceFiles(sourceDir, targetDir);
Which will check the current files in the source, and then recursively look through all source subdirectories.
private static void OperateOnSourceFiles(string source, string targetDir)
{
//Processes current source folder files
foreach (var file in Directory.GetFiles(source))
{
OverWrite(targetDir, file);
}
//Recursively processes files in source subfolders
List<string> subfolders = Directory.GetDirectories(source).ToList();
foreach (var subfolder in subfolders)
{
OperateOnSourceFiles(subfolder, targetDir);
}
}
Then your overwrite function could look something like this:
private static void OverWrite(string target, string sourcefile)
{
//Grab file name
var strSrcFile = sourcefile.Split(Path.DirectorySeparatorChar).Last();
//Search current target directory FILES, and copy only if same file name
List<string> targetfiles = Directory.GetFiles(target).Select(file=>file.Split(Path.DirectorySeparatorChar).Last()).ToList();
if (targetfiles.Contains(strSrcFile))
{
File.Copy(sourcefile, Path.Combine(target, Path.GetFileName(strSrcFile)), true);
}
//Recursively search current target directory SUBFOLDERS if any
List<string> subfolders = Directory.GetDirectories(target).ToList();
foreach (var subfolder in subfolders)
{
OverWrite(subfolder, sourcefile);
}
}
Feel free to correct me :)
Note: I realize it's still quite a lot of foreach loops, but at least they aren't nested, and makes life easier when debugging.
I liked the idea, so I tried this myself. Turned out a bit more complicated then I thought it would. Let's go into a deep dive, okay?
The basic idea is to synchronize directories, so we want references to DirectoryInfo instances.
var source = new DirectoryInfo(#"C:\SynchSource");
var target = new DirectoryInfo(#"C:\SynchTarget");
Synchronize(source, target);
Synchronize pretty much works in the following manner:
make sure all files are identical
make sure all directories are identical
go through all subdirectories and traverse
My implementation looks like this:
void Synchronize(DirectoryInfo sourceDir, DirectoryInfo targetDir)
{
SynchronizeFiles(sourceDir, targetDir);
SynchronizeDirectories(sourceDir, targetDir);
TraverseDirectories(sourceDir, targetDir);
}
Note the .Single() - we can never assume there is just one person/process working in the directories.
SynchronizeFiles does two things:
Copy/overwrite all files in the current directory into the target directory.
Remove redundant files that no more exist in the source directory
void MoveFiles(DirectoryInfo sourceDir, DirectoryInfo targetDir)
{
foreach (FileInfo sourceFile in sourceDir.GetFiles())
{
string targetFilePath = Path.Combine(targetDir.FullName, sourceFile.Name);
File.Copy(sourceFile.FullName, targetFilePath);
}
}
void RemoveRedundantFiles(DirectoryInfo sourceDir, DirectoryInfo targetDir)
{
foreach (var targetFile in targetDir.GetFiles())
{
var sourceFilePath = Path.Combine(sourceDir.FullName, targetFile.Name);
if (!File.Exists(sourceFilePath))
{
targetFile.Delete();
}
}
}
We can now assume all files in the current directory are the same, no more and no less. In order to traverse through the subdirectories, we first have to make sure the directory structure is the same. We do it in a similar manner to SynchronizeFiles:
Create missing directories in the target directory (CreateMissingDirectories)
Remove redundant directories that no more exist in the source directory (RemoveRedundantDirectories)
void CreateMissingDirectories(DirectoryInfo sourceDir, DirectoryInfo targetDir)
{
foreach (DirectoryInfo sourceSubDir in sourceDir.GetDirectories())
{
string targetSubDirPath = Path.Combine(targetDir.FullName, sourceSubDir.Name);
if (!Directory.Exists(targetSubDirPath))
{
Directory.CreateDirectory(targetSubDirPath);
}
}
}
void RemoveRedundantDirectories(DirectoryInfo sourceDir, DirectoryInfo targetDir)
{
foreach (DirectoryInfo targetSubDir in targetDir.GetDirectories())
{
string sourceSubDirPath = Path.Combine(sourceDir.FullName, targetSubDir.Name);
if (!Directory.Exists(sourceSubDirPath))
{
targetSubDir.Delete(true);
}
}
}
We are at the state that files and directories in the current level of hierarchy equal. We can now iterate through all subdirectories and call Synchronize:
void TraverseDirectories(DirectoryInfo sourceDir, DirectoryInfo targetDir)
{
foreach (DirectoryInfo sourceSubDir in sourceDir.GetDirectories())
{
DirectoryInfo targetSubDir = targetDir.GetDirectories(sourceSubDir.Name).Single();
Synchronize(sourceSubDir, targetSubDir);
}
}
And we are done.
For huge directory hierarchies, a big amount or large files or even concurrent processes working in the directory, there is much room for improvement. There is a lot of work to do for it to be fast (you may want to cache GetFiles / GetDirectories), skip unnecessary File.Copy calls (get a file hash before assuming a copy is needed).
Just as a side note: Other than synchronizing files every now and then, depending on the requirement, you may want to have a look at FileSystemWatcher, which can detect all changes recursively in a selected directory.

How to get list of directories containing particular file using c#

I wish to get list of all the folders/directories that has a particular file in it. How do I do this using C# code.
Eg: Consider I have 20 folders of which 7 of them have a file named "abc.txt". I wish to know all folders that has the file "abc.txt".
I know that we can do this by looking thru all the folders in the path and for each check if the File.Exists(filename); But I wish to know if there is any other way of doing the same rather than looping through all the folder (which may me little time consuming in the case when there are many folders).
Thanks
-Nayan
I would use the method EnumerateFiles of the Directory class with a search pattern and the SearchOption to include AllDirectories. This will return all files (full filename including directory) that match the pattern.
Using the Path class you get the directory of the file.
string rootDirectory = //your root directory;
var foundFiles = Directory.EnumerateFiles(rootDirectory , "abc.txt", SearchOption.AllDirectories);
foreach (var file in foundFiles){
Console.WriteLine(System.IO.Path.GetDirectoryName(file));
}
EnumerateFiles is only available since .NET Framework 4. If you are working with an older version of the .NET Framework then you could use GetFiles of the Directory class.
Update (see comment from PLB):
The code above will fail if the access to a directory in denied. In this case you will need to search each directory one after one to handle exceptions.
public static void SearchFilesRecursivAndPrintOut(string root, string pattern)
{
//Console.WriteLine(root);
try
{
var childDireactory = Directory.EnumerateDirectories(root);
var files = Directory.EnumerateFiles(root, pattern);
foreach (var file in files)
{
Console.WriteLine(System.IO.Path.GetDirectoryName(file));
}
foreach (var dir in childDireactory)
{
SearchRecursiv(dir, pattern);
}
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
}
The following shows how to narrow down your search by specific criteria (i.e. include only DLLs that contain "Microsoft", "IBM" or "nHibernate" in its name).
var filez = Directory.EnumerateFiles(#"c:\MLBWRT", "*.dll", SearchOption.AllDirectories)
.Where(
s => s.ToLower().Contains("microsoft")
&& s.ToLower().Contains("ibm")
&& s.ToLower().Contains("nhibernate"));
string[] allFiles = filez.ToArray<string>();
for (int i = 0; i < allFiles.Length; i++) {
FileInfo fInfo = new FileInfo(allFiles[i]);
Console.WriteLine(fInfo.Name);
}

Moving files based on name to the corresponding folder

Hello everyone and well met! I have tried a lot of different methods/programs to try and solve my problem. I'm a novice programmer and have taken a Visual Basic Class and Visual C# class.
I'm working with this in C#
I started off by making a very basic move file program and it worked fine for one file but as I mentioned I will be needing to move a ton of files based on name
What I am trying to do is move .pst (for example dave.pst) files from my exchange server based on username onto a backup server in the users folder (folder = dave) that has the same name as the .pst file
The ideal program would be:
Get files from the folder with the .pst extension
Move files to appropriate folder that has the same name in front of the .pst file extension
Update:
// String pstFileFolder = #"C:\test\";
// var searchPattern = "*.pst";
// var extension = ".pst";
//var serverFolder = #"C:\test3\";
// String filename = System.IO.Path.GetFileNameWithoutExtension(pstFileFolder);
// Searches the directory for *.pst
DirectoryInfo sourceDirectory = new DirectoryInfo(#"C:\test\");
String strTargetDirectory = (#"C:\test3\");
Console.WriteLine(sourceDirectory);
Console.ReadKey(true);>foreach (FileInfo file in sourceDirectory.GetFiles()) {
Console.WriteLine(file);
Console.ReadKey(true);
// Try to create the directory.
System.IO.Directory.CreateDirectory(strTargetDirectory);
file.MoveTo(strTargetDirectory + "\\" + file.Name);
}
This is just a simple copy procedure. I'm completely aware. The
Console.WriteLine(file);
Console.ReadKey(true);
Are for verification purpose right now to make sure I'm getting the proper files and I am. Now I just need to find the folder based on the name of the .pst file(the folder for the users are already created), make a folder(say 0304 for the year), then copy that .pst based on the name.
Thanks a ton for your help guys. #yuck, thanks for the code.
Have a look at the File and Directory classes in the System.IO namespace. You could use the Directory.GetFiles() method to get the names of the files you need to transfer.
Here's a console application to get you started. Note that there isn't any error checking and it makes some assumptions about how the files are named (e.g. that they end with .pst and don't contain that elsewhere in the name):
private static void Main() {
var pstFileFolder = #"C:\TEMP\PST_Files\";
var searchPattern = "*.pst";
var extension = ".pst";
var serverFolder = #"\\SERVER\PST_Backup\";
// Searches the directory for *.pst
foreach (var file in Directory.GetFiles(pstFileFolder, searchPattern)) {
// Exposes file information like Name
var theFileInfo = new FileInfo(file);
// Gets the user name based on file name
// e.g. DaveSmith.pst would become DaveSmith
var userName = theFileInfo.Name.Replace(extension, "");
// Sets up the destination location
// e.g. \\SERVER\PST_Backup\DaveSmith\DaveSmith.pst
var destination = serverFolder + userName + #"\" + theFileInfo.Name;
File.Move(file, destination);
}
}
System.IO is your friend in this case ;)
First, Determine file name by:
String filename = System.IO.Path.GetFileNameWithoutExtension(SOME_PATH)
To make path to new folder, use Path.Combine:
String targetDir = Path.Combine(SOME_ROOT_DIR,filename);
Next, create folder with name based on given fileName
System.IO.Directory.CreateDirectory(targetDir);
Ah! You need to have name of file, but with extension this time. Path.GetFileName:
String fileNameWithExtension = System.IO.Path.GetFileName(SOME_PATH);
And you can move file (by File.Move) to it:
System.IO.File.Move(SOME_PATH,Path.Combine(targetDir,fileNameWithExtension)
Laster already show you how to get file list in folder.
I personally prefer DirectoryInfo because it is more object-oriented.
DirectoryInfo sourceDirectory = new DirectoryInfo("C:\MySourceDirectoryPath");
String strTargetDirectory = "C:\MyTargetDirectoryPath";
foreach (FileInfo file in sourceDirectory.GetFiles())
{
file.MoveTo(strTargetDirectory + "\\" + file.Name);
}

Categories