So this seems to me to be a simple looping issue it's just that I keep confusing myself over the logic.
So I want to count all the files within a folder, and then all the folders within that folder, I want to count the files that are in there too.
Which mean I have to loop through to check wether there is a folder and then check it until there are no more folders. But I can't write the algoritm because I keep confusing myself.
I'm pretty sure there is a standard algorithm for something like this but I can't remember the name.
This is what I have so far:
var rootDir = Directory.GetDirectories(#"C:\");
foreach (var dir in rootDir)
{
if (Directory.GetDirectories(dir).Length > 0)
{
}
}
Do I understand right, you need to count only files in folder and all subfolders? Directory.GetFiles has option for review all subfolders. Try this
Directory.GetFiles(WorkingDir, "*", SearchOption.AllDirectories);
use GetFiles
Directory.GetFiles
// 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);
}
// Insert logic for processing found files here.
public static void ProcessFile(string path)
{
Console.WriteLine("Processed file '{0}'.", path);
}
here is a solution to count all files files and number of file per dir: i am using a dictionary to stock all datas
class Program
{
public static Dictionary<string, int> dico = new Dictionary<string, int>();
public static void CountFiles(string nameDirectory)
{
int nbrfiles = Directory.GetFiles(nameDirectory).Length;
dico[targetDirectory] = nbrfiles;
string[] subdirectories = Directory.GetDirectories(nameDirectory);
foreach (string subdir in subdirectories)
CountFiles(subdir);
}
static void Main(string[] args)
{
string tdir = "e:\\example";
CountFiles(tdir);
var totalfiles = dico.Sum(x => x.Value);
Console.WriteLine($"Directory {tdir} contains {totalfiles} files");
foreach (var item in dico)
{
Console.WriteLine($"Directory {item.Key} has {item.Value} file(s)");
}
}
}
Related
How to delete Files there names containing a specific string in a Directory and also all Subdirectories?
Given Filenames like:
EA myown EURJPY M15 3015494.mq5
EA myown EURJPY M15 3015494.ex5
EA self EURJPY M15 3098111 fine.mq5
EA self EURJPY M15 3098111 fine.ex5
Given Folderstructures like:
D:\TEMP\MYTEST
D:\TEMP\MYTEST\EURJPY
D:\TEMP\MYTEST\EURJPY\EURJPY_M15
Example: I want to delete ALL Files in all Subdirectories containing this String:
3015494
These Files are copied more than one time down of the Root-Folder "D:\TEMP\MYTEST" and also copied into the Subdirectories.
I try to write a little function for this. But i can delete Files into a given Folder, but not down into Subfolders ...
Last Code from me:
// call my function to delete files ...
string mypath = #"D:\TEMP\MYTEST\";
string myfilecontains = #"xx";
DeleteFile(mypath, true, myfilecontains);
// some code i found here and should delete just Files,
// but only works in Root-Dir.
// Also will not respect my need for Filename contains Text
public static bool DeleteFile(string folderPath, bool recursive, string FilenameContains)
{
//Safety check for directory existence.
if (!Directory.Exists(folderPath))
return false;
foreach (string file in Directory.GetFiles(folderPath))
{
File.Delete(file);
}
//Iterate to sub directory only if required.
if (recursive)
{
foreach (string dir in Directory.GetDirectories(folderPath))
{
//DeleteFile(dir, recursive);
MessageBox.Show(dir);
}
}
//Delete the parent directory before leaving
//Directory.Delete(folderPath);
return true;
}
What i have to change in this Code for my needs?
Or is there a complete different code something more helpfull?
I hope you have some good ideas for me to catch the trick.
DirectoryInfo dir = new DirectoryInfo(mypath);
// get all the files in the directory.
// SearchOptions.AllDirectories gets all the files in subdirectories as well
FileInfo[] files = dir.GetFiles("*.*", SearchOption.AllDirectories);
foreach (FileInfo file in files)
{
if (file.Name.Contains(myfilecontains))
{
File.Delete(file.FullName);
}
}
This is similar to hossein's answer but in his answer if the directory name contains the value of myfilecontains that file will get deleted as well which I would think you don't want.
//get the list of files in the root directory and all its subdirectories:
string mypath = #"D:\TEMP\MYTEST\";
string myfilecontains = #"xx";
var files = Directory.GetFiles(mypath, "*", SearchOption.AllDirectories).ToList<string>();
//get the list of file for remove
var forDelete = files.Where(x => x.Contains(myfilecontains));
//remove files
forDelete.ForEach(x => { File.Delete(x); });
hope this helps!
I have a Main directory which has a bunch of sub directories , Each of these sub directories are expected to have an app.config file and I want to validate it . This app.config file can be any where of a given sub directory.
As of my implementation below I can check if this config file is immediately inside the given subdirectory (for example if the sub directory is "folder" I will check if the app.confg is available in the path folder\app.config ) but it fails to check if the app.config is in any where of the given sub directory.
IN the sense the app.config file can be inside of a sub direcotry of a given inital sub directory. bascically anywhere inside the given sub directory
Is there any way I can implement this behavior ?
private void ValidateFiles(string path)
{
string[] filesindirectory = Directory.GetDirectories(path);
foreach (var subDir in filesindirectory)
{
string pathToConfigFile = Path.Combine(subDir, "app.config");
if (File.Exists(pathToConfigFile))
{
}
else
{
}
}
}
You can use the Directory.GetFiles method to find your file inside a folder and in the SearchOption parameter pass the SearchOption.AllDirectories to search in all subdirectories.
Here is the code sample for reference:
private void ValidateFiles(string path)
{
var filesindirectory = Directory.GetFiles(path, "app.config", SearchOption.AllDirectories);
foreach (var file in filesindirectory)
{
Console.WriteLine(file);
}
}
In the filesindirectory variable you will now have all the file names(which is app.config in our case) along with the path.
For more reference : Microsoft Doc
Using Recursion if your path contains subdirectories inside subdirectories.
private void ValidateFiles(string path)
{
DirSearch(path);
}
private void DirSearch(string sDir)
{
List<String> files = new List<String>();
try
{
foreach (string f in Directory.GetFiles(sDir))
{
string pathToConfigFile = Path.Combine(sDir, "app.config");
if (File.Exists(pathToConfigFile))
{
}
else
{
}
}
foreach (string d in Directory.GetDirectories(sDir))
{
files.AddRange(DirSearch(d));
}
}
catch (System.Exception excpt)
{
MessageBox.Show(excpt.Message);
}
}
var LstfileDirectory = Directory.GetFiles(path, "app.config",
SearchOption.AllDirectories)
.ToList();
LstfileDirectory.ForEach(Item => Console.WriteLine(Item));
I have a .NET webform that is displaying files found in a directory in a listView. This is the code for the display:
private void files()
{
try
{
DirectoryInfo dinfo = new DirectoryInfo(label2.Text);
FileInfo[] Files = dinfo.GetFiles("*.doc");
foreach (FileInfo file in Files)
{
listView1.Items.Add(file.Name);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
label2.Text contains the directory that houses the files. What I need is for a second listView to display a list of documents housed in another directory to display if the file does not appear in the first list view.
The second directory contains templates where as the first directory contains completed documents. The names are different in each directory, but they are similar. For example a completed document displayed in the first listView may be called DEFECT1_AA09890.doc. It's template may be called 05DEFECT.doc.
It is easy enough to display the contents of the template directory using this code:
private void templateDocuments()
{
string path = #"\\directoryname\foldername";
try
{
DirectoryInfo dinfo = new DirectoryInfo(path);
FileInfo[] Files = dinfo.GetFiles("*.doc");
foreach (FileInfo file in Files)
{
listView2.Items.Add(file.Name);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
But this does not compare contents and display based on the results.
Long story short, I want to display the contents of a directory in a listView, compare it to the contents of another directory, and display in a second listView what does not appear in the first.
Any help would be much appreciated.
Cheers.
Before adding file names to listView2, you need to check whether you already added them to listView1. One way of doing that is to store the files in listView1 in a HashSet<string>, then checking that before adding to listView2. Something like this should work:
private void filesAndTemplates()
{
string path = #"\\directoryname\foldername";
HashSet<string> files = new HashSet<string>();
try
{
DirectoryInfo dinfo = new DirectoryInfo(label2.Text);
FileInfo[] Files = dinfo.GetFiles("*.doc");
foreach (FileInfo file in Files)
{
files.Add(file.Name);
listView1.Items.Add(file.Name);
}
dinfo = new DirectoryInfo(path);
Files = dinfo.GetFiles("*.doc");
foreach (FileInfo file in Files)
{
if (files.Contains(file.Name))
{
continue; // We already saw this file
}
listView2.Items.Add(file.Name);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
EDIT
If you want inexact matching, you need to reduce the file name to its essence -- remove any decorations, which in your case looks to be one (or both) of
Leading digits
Underscore followed by whatever
The essence of 01hello_world.doc would thus be hello.
Regex should fit the bill quite nicely -- although the exact definition of the regular expression would depend on your exact requirements.
Define the Regex and a transformation method somewhere suitable:
private static readonly Regex regex = new Regex(
#"[0-9]*(?<core>[^_]+)(_{1}.*)?", RegexOptions.Compiled);
private static string Transform(string fileName)
{
int extension = fileName.LastIndexOf('.');
if (extension >= 0)
{
fileName = fileName.Substring(0, extension);
}
Match match = regex.Match(fileName);
if (match.Success)
{
return match.Groups["core"].Value;
}
return fileName;
}
Then modify the original method to transform the filename before adding files to the HashSet and before checking for their presence:
DirectoryInfo dinfo = new DirectoryInfo(label2.Text);
FileInfo[] Files = dinfo.GetFiles("*.doc");
foreach (FileInfo file in Files)
{
files.Add(Transform(file.Name)); // Here!
listView1.Items.Add(file.Name);
}
dinfo = new DirectoryInfo(path);
Files = dinfo.GetFiles("*.doc");
foreach (FileInfo file in Files)
{
if (files.Contains(Transform(file.Name))) // Here!
{
continue;
}
listView2.Items.Add(file.Name);
}
Note the two calls to Transform.
I'm trying this function, which copies all files from a folder, and relative subfolders with files to another location:
using System.IO;
private static bool CopyDirectory(string SourcePath, string DestinationPath, bool overwriteexisting)
{
bool ret = true;
try
{
SourcePath = SourcePath.EndsWith(#"\") ? SourcePath : SourcePath + #"\";
DestinationPath = DestinationPath.EndsWith(#"\") ? DestinationPath : DestinationPath + #"\";
if (Directory.Exists(SourcePath))
{
if (Directory.Exists(DestinationPath) == false)
Directory.CreateDirectory(DestinationPath);
foreach (string fls in Directory.GetFiles(SourcePath))
{
FileInfo flinfo = new FileInfo(fls);
flinfo.CopyTo(DestinationPath + flinfo.Name, overwriteexisting);
}
foreach (string drs in Directory.GetDirectories(SourcePath))
{
DirectoryInfo drinfo = new DirectoryInfo(drs);
if (CopyDirectory(drs, DestinationPath + drinfo.Name, overwriteexisting) == false || drs.Substring(drs.Length-8) == "archive")
ret = false;
}
}
else
{
ret = false;
}
}
catch (Exception e)
{
Console.WriteLine("{0} {1} {2}", e.Message, Environment.NewLine + Environment.NewLine, e.StackTrace);
ret = false;
}
return ret;
}
It works good until you have to copy the folder into another location, but when you have to create a folder in itself (In my example I'm doing a subfolder called "archive" to keep track of the last folder files changes) it goes in infinite loops, because it keeps rescanning itself in the Directory.GetDirectories foreach loop, finding the newly created subfolders and going on nesting the same subfolder over and over until it reaches a "Path name too long max 260 charachters limit exception".
I tried to avoid it by using the condition
|| drs.Substring(drs.Length-8) == "archive")
which should check the directory name, but it doesn't seem to work.
I thought than, different solutions like putting a max subfolders depth scan (I.E max 2 subfolders) so it doesn't keep rescanning all the nested folders, but I can't find such property in Directory object.
I cannot copy the whole thing to a temp folder and then into the real folder because the next time I will scan it, it will rescan archive folder too.
I tought about putting all the directory listing in an ArrayList of Directory objects or so so maybe I can check something like DirName or so but I don't know if such property exists.
Any solution?
This is a case where recursion doesn't really work, as the list of directories and files always changes as you copy. A better solution is to get the list of all files and folders in advance.
You can get all files and directories in a tree using the Directory.GetFiles(String,String,SearchOption) and Directory.GetDirectories(String,String,SearchOption) with SearchOption set to SearchOption.AllDirectories. These will return all files and all directories respectively.
You can follow these steps to copy the files:
Get the list of all source directories and sort them in ascending order. This will ensure that parent directories appear before their child directories.
Create the target directory structure by creating the child directories in their sorted order. You won't get any path conflicts as the sort order ensures you always create the parent folders before the child folders
Copy all the source files to the target directories as before. Order doesn't really matter at this point as the target directory structure already exists.
A quick example:
static void Main(string[] args)
{
var sourcePath = #"c:\MyRoot\TestFolder\";
var targetPath = #"c:\MyRoot\TestFolder\Archive\";
var directories=Directory.GetDirectories(sourcePath, "*", SearchOption.AllDirectories);
var files = Directory.GetFiles(sourcePath, "*", SearchOption.AllDirectories);
if(!Directory.Exists(targetPath))
Directory.CreateDirectory(targetPath);
foreach (var directory in directories)
{
var relativePath = GetRelativePath(sourcePath, directory);
var toPath = Path.Combine(targetPath, relativePath);
if (!Directory.Exists(toPath))
{
Directory.CreateDirectory(toPath);
}
}
foreach (var file in files)
{
var relativePath = GetRelativePath(sourcePath, file);
var toPath = Path.Combine(targetPath, relativePath);
if (!File.Exists(toPath))
File.Copy(file,toPath);
}
}
//This is a very quick and dirty way to get the relative path, only for demo purposes etc
private static string GetRelativePath(string rootPath, string fullPath)
{
return Path.GetFullPath(fullPath).Substring(rootPath.Length);
}
I need to get path for each file in directories
eg: c:/a/b/c/1.jar and c:/dir/bin/2.jar must be saved as string
"c:/a/b/c/1.jar; c:/dir/bin/2.jar;..."
But the folders name may change in the future and I don't want to write this manually
Thanks for help
EDIT 1:
I've got the folder with few folders into. in each folder is files. I need to get all files directory in one string. eg: "dir1; dir2; dir3; ..."
but I can give only directory of main folder "c:/bin"
EDIT 2: Solved by Sayse
You can use Directory.EnumerateFiles
var allFiles = Directory.EnumerateFiles(sourceDirectory,
"*.*", //also can use "*.jar" here for just jar files
SearchOption.AllDirectories);
If you wish for all files to be in one long string then you can use
var fileString = string.Join(",", allFiles);
If its only directories you want
var allDirs = Directory.EnumerateDirectories("...",
"*",
SearchOption.AllDirectories);
var dirString = string.Join(";", allDirs);
class Program
{
static void Main(string[] args)
{
DirectoryInfo di = new DirectoryInfo("C:\\");
FullDirList(di, "*");
Console.WriteLine("Done");
Console.Read();
}
static string myfolders = "";// Your string, which inclueds the folders like this: "c:/a/b/c; c:/dir/bin;..."
static string myfiles = ""; // Your string, which inclueds the file like this: "c:/a/b/c/1.jar; c:/dir/bin/2.jar;..."
static List<FileInfo> files = new List<FileInfo>(); // List that will hold the files and subfiles in path
static List<DirectoryInfo> folders = new List<DirectoryInfo>(); // List that hold direcotries that cannot be accessed
static void FullDirList(DirectoryInfo dir, string searchPattern)
{
// Console.WriteLine("Directory {0}", dir.FullName);
// list the files
try
{
foreach (FileInfo f in dir.GetFiles(searchPattern))
{
//Console.WriteLine("File {0}", f.FullName);
files.Add(f);
myfiles += f.FullName + ";";
}
}
catch
{
Console.WriteLine("Directory {0} \n could not be accessed!!!!", dir.FullName);
return; // We alredy got an error trying to access dir so dont try to access it again
}
// process each directory
// If I have been able to see the files in the directory I should also be able
// to look at its directories so I dont think I should place this in a try catch block
foreach (DirectoryInfo d in dir.GetDirectories())
{
myfolders += d.FullName + ";";
folders.Add(d);
FullDirList(d, searchPattern);
}
}
}
myfiles includes all files , like "C:\MyProgram1.exe;C:\MyFolder\MyProgram2.exe;C:\MyFolder2\MyProgram2.dll"
myfolder inclueds all folders, like "C:\MyFolder;C:\MyFolder2";