Accessing files within child directories - c#

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

Related

How to get approximate file path?

I have a list file path as follow:
C:\Data\Default.aspx
C:\Data\Global.asax
C:\Data\Web.config
C:\Data\bin\PerlsComWebProject1.dll
C:\Data\bin\PerlsComWebProject1.pdb
I have a method to get file from folder path, however I want to print result as below:
Data\Default
Data\Global
Data\Web.config
Data\bin\PerlsComWebProject1
Data\bin\PerlsComWebProject1
Call: GetFilePathWithOutExtention(#"C:\\Data");
My code is only return file without an extension.
void GetFilePathWithOutExtention(string path)
{
string[] paths = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
foreach(var path in paths)
{
Console.WriteLine(Path.GetFileNameWithoutExtension(path));
}
}
Update: Thanks for your comments. "C:\Data\" is only a sample, sorry so make you confused. Actual, I have a any folder, I want to search this folder, get approximate path: this folder...\filename with out extention.
Ex: I have a path as follow: D:\EHO\Phase1\Data\Document\text.txt,....when I call method: GetFilePathWithOutExtention("D:\EHO\Phase1"), I want to output: Phase1\Data\Document\text, or GetFilePathWithOutExtention("D:\EHO\Phase1\Data"), output: Data\Document\text.
Thanks.
I think what you're looking for is Uri.MakeRelativeUri
So you could do something like this:
var folder = new Uri(#"C:\Data");
var paths = System.IO.Directory.GetFiles(folder.LocalPath, "*.*", System.IO.SearchOption.AllDirectories);
foreach (var uri in paths.Select(p => new Uri(p)))
{
Console.WriteLine(folder.MakeRelativeUri(uri).ToString());
}
This prints
Data/Default.aspx
Data/Global.asax
Data/Web.config
Data/bin/PerlsComWebProject1.dll
Data/bin/PerlsComWebProject1.pdb
A generic answer, valid for all folders inside the machine drives, not only 1st level:
void GetFilePathWithOutExtention(string path)
{
// Get the name of the folder containing your path (for further remove in the items folder)
string parentFolderName = Directory.GetParent(path).FullName;
string[] filePaths = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
foreach(string fileItemPath in filePaths)
{
// Get the current folder without the initial folder path
string currentItemPath = Path.GetDirectoryName(fileItemPath).Remove(0, parentFolderName.Length);
Console.WriteLine(Path.Combine(currentItemPath, Path.GetFileNameWithoutExtension(fileItemPath)));
}
}
you can just Show from the 4th char
void GetFilePathWithOutExtention(string path)
{
string[] filesName = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
foreach(var fileName in filesName)
{
string pathToWrite = Path.GetFileNameWithoutExtension(fileName);
if(pathToWrite != null && pathToWrite.length >3 )
Console.WriteLine(pathToWrite.Substring(3,pathToWrite.length);
}
}

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.

Searching through a file structure to count items in a subfolder

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.

How to get sub-directory names and files from a folder dragged and dropped onto an application

I have the following code, which will process the folder and files in that folder when a user drops it onto a button on my C# Winforms application window. This code works fine:
List<string> filepaths = new List<string>();
foreach (var s in (string[])e.Data.GetData(DataFormats.FileDrop, false))
{
if (Directory.Exists(s))
{
//Add files from folder
filepaths.AddRange(Directory.GetFiles(s));
}
else
{
//Add filepath
filepaths.Add(s);
}
}
However, if there is another folder inside of the main folder (sub-folder), it does not detect that sub-folder and list the files inside of the sub-folder.
Can someone please show me how to detect the name of the sub-folder and the files in the sub-folder as well?
Edit: Would something like this work?
string[] fileList = Directory.GetFiles(#s, "*.*", SearchOption.AllDirectories);
Simalar to Frazell but I like to use file and directory info types like:
Edit: Added a ProcessFile() method
public void ProcessFolder(DirectoryInfo dirInfo)
{
//Check for sub Directories
foreach (DirectoryInfo di in dirInfo.GetDirectories())
{
//Call itself to process any sub directories
ProcessFolder(di);
}
//Process Files in Directory
foreach (FileInfo fi in dirInfo.GetFiles())
{
//Do something with the file here
//or create a method like:
ProcessFile(fi)
}
}
public void ProcessFile(FileInfo fi)
{
//Do something with your file
Debug.Print(fi.FullName);
//...
}
You need to use Directory.GetDirectories() to pull back the subdirectories then loop through them similar to what you're already doing.
// Process all files in the directory passed in, recurse on any directories
// that are found, and process the files they contain.
public static void ProcessDirectory(string targetDirectory)
{
// Process the list of files found in the directory.
string [] fileEntries = Directory.GetFiles(targetDirectory);
foreach(string fileName in fileEntries)
ProcessFile(fileName);
// Recurse into subdirectories of this directory.
string [] subdirectoryEntries = Directory.GetDirectories(targetDirectory);
foreach(string subdirectory in subdirectoryEntries)
ProcessDirectory(subdirectory);
}
Source: MSDN

Directory is not reading properly

I am having One Directory
C:\Kuldeep\kverma\kver\
After that It consists thousands of Folders with Different name .Each Folder consists Different Excel File . I need to read Each Files from Different Folders .
I want To read All The Folders Path from C:\Kuldeep\kverma\kver\ Folder.
I used below code for getting the folders name with path ..
string path = #"C:\Kuldeep\kverma\kver\";
DirectoryInfo dir = new DirectoryInfo(path);
Console.WriteLine("File Name Size Creation Date and Time");
Console.WriteLine("========");
foreach (DirectoryInfo dirinfo in dir.GetDirectories())
{
String name = dirinfo.Name;
String pth = dirinfo.FullName;
Console.WriteLine( name, pth);
}
Total 10700 folders are there in C:\Kuldeep\kverma\kver\ Directory But It is reading only 54 Folder..
Please provide me any solution for Reading Folder name and location Also Reading File from Each Folder in Single Shot .
You should put a try catch around the GetDirectories call to handle the exceptions in the below post.
That might give you a clue as to why it is not enumerating properly.
http://msdn.microsoft.com/en-us/library/c1sez4sc.aspx
Try a recursive approach:
namespace ConsoleApplication1
{
using System;
using System.Collections.Generic;
using System.IO;
class Program
{
public static IList<DirectoryInfo> dirs;
static void Main(string[] args)
{
dirs = new List<DirectoryInfo>();
var dir = new DirectoryInfo(#"c:\tmp");
GetDirs(dir);
Console.WriteLine(dirs.Count);
}
public static void GetDirs(DirectoryInfo root)
{
foreach (var directoryInfo in root.GetDirectories())
{
dirs.Add(directoryInfo);
GetDirs(directoryInfo);
}
}
}
}
Now I'm not sure what hidden dangers might be lurking because of this (Stack overflow exceptions, access denied?) so I'd recommend placing a try..catch block in the foreach loop to help you out.
If you want to view the contents of every sub directory:
// Flatten out the directory structure in to a string array.
var directoryList = Directory.GetDirectories("<<RootPath>>", "*", SearchOption.AllDirectories);
foreach (var directory in directoryList)
{
DirectoryInfo info = new DirectoryInfo(directory);
}
edited with the questions code updated:
string path = #"C:\Kuldeep\kverma\kver\";
string[] directoryArray = Directory.GetDirectories(path, "*", SearchOption.AllDirectories);
foreach (var directory in directoryArray)
{
DirectoryInfo dirinfo = new DirectoryInfo(directory);
String name = dirinfo.Name;
String pth = dirinfo.FullName;
Console.WriteLine(name, pth);
}

Categories