Count the number of files with specific extension - c#

:)
So I have a hw (I have to run project from console): I have to count the number of sub directories in specific directory (the user writes in this way " [path] [extension] [-r] ")
So if user writes the directory and doesn't write the extension, my program just counts the number of sub directories.
BUT if user writes the parameter, for example, .exe, .txt, .cs, I have to count the number of files with this specific extension in the specific directory and return this number.
Sooo, everything is good with the first part - my program works correctly and count the number of sub directories, recursively (if I write the parameter -r) or not (if I don't). The problem is with counting files with extension.
Here is my function for counting sub directories:
class Data
{
public string curDir = Directory.GetCurrentDirectory();
public string Extension = "";
public bool isRecursive;
}
public static int CountDir(Data data)
{
string[] dirs = Directory.GetDirectories(data.curDir);
int res = dirs.Length;
int resFiles = files.Length;
try
{
if (data.isRecursive)
{
foreach (string subdir in dirs)
{
Data d = new Data();
d.curDir = subdir;
d.Extension = data.Extension;
d.isRecursive = data.isRecursive;
res += CountDir(d);
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex.Message}");
}
return res;
}
So I tried to do the similar thing in this method, but for files and I'm a bit confused:
string[] files = Directory.GetFiles(data.curDir);
int resFiles = files.Length;
foreach (string ext in files)
{
FileInfo fi = new FileInfo(ext);
if (data.Extension != "")
{
if (fi.Extension == data.Extension)
{
//res = 0;
//++res;
//what am I supposed to do here?..
}
}
}
I also wonder if I can do this in the same method (CountDir).
Thank you so much in advance!
Edit: I know about SearchOptions.AllDirectories method, but I don't know in advance which extension user will write

I would put the file count logic in its own method since the goal is to get the number of files for a specific directory rather than all sub-directories. Here's an example based on your sample code:
public static int countFiles(Data data)
{
string[] files = new string[0];
try
{
files = Directory.GetFiles(data.curDir, $"*{data.Extension}");
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex.Message}");
}
return files.Length;
}

Related

Issue trying to count number of file in directories + subdirectories

As the title says I'm trying to count the number of file in a directory and subdirectories.
I tried with a foreach loop like that :
public static int hello(string path)
{
string[] files = Directory.GetFiles(path);
string[] dirs = Directory.GetDirectories(path);
int cpt = 0;
foreach (var file in files)
{
try
{
Console.WriteLine(file);
cpt++;
}
catch { }
}
foreach (var directory in dirs)
{
try
{
hello(directory);
}
catch { }
}
return cpt;
}
And the returned value is always the number of file contained in the first path, the cpt var don't get incremented by the number of files in the others directories and subdirectories.
It's strange since the Console.WriteLine(file) shows all the files path in the console box.
It looks like a small issue but I don't really know how to solve it, I don't want to use SearchOption method but I really want to use cpt and increment it at each file.
SOLVED with the following code :
public static int hello(string path)
{
string[] files = Directory.GetFiles(path);
string[] dirs = Directory.GetDirectories(path);
int cpt = 0;
foreach (var file in files)
{
try
{
Console.WriteLine(file);
cpt++;
}
catch { }
}
foreach (var directory in dirs)
{
try
{
cpt+=hello(directory);
}
catch { }
}
return cpt;
}
Thanks to #steryd !
When you descend down the directories you're not saving the count. cpt is unique for each invocation of hello()

c# finding files with some extension on hard disk

I want to find all files in whole harddrive (.jpg, .png, .apk and a few other formats) but this code is not working..all it does is : for example if in my 'D:\' drive I have: 1)a image file 'i1', 2)a folder 'f1' which has image file and 3) another folder 'f2' which has image file and 'f2' contains folder 'f3' which has image file .It only performs 'calcFile()' on contents inside f1 and f2 but not on contents of f3 and i1 same happens with all other partitions .What is wrong here? Any help is appreciated.
I hope you understand what is happening because that's the easiest way I could explain my situation, if more info is required just tell me. thanks :)
public void calcDirectory(string token)
{
var validExtensions = new[]
{
".jpg", ".png", ".apk"
};
foreach (string s in Directory.GetLogicalDrives())
{
DriveInfo driveInfo = new DriveInfo(s);
if (driveInfo.IsReady)
{
foreach (string d in Directory.GetDirectories(s))
{
FileAttributes attrs1 = File.GetAttributes(d);
if (!attrs1.HasFlag(FileAttributes.ReparsePoint))
{
if (!attrs1.HasFlag(FileAttributes.System))
{
string[] allFilesInDir = Directory.GetFiles(d);
for (int i = 0; i < allFilesInDir.Length; i++)
{
string file = allFilesInDir[i];
string extension = Path.GetExtension(file);
if (validExtensions.Contains(extension))
{
string p = Path.GetFullPath(file);
FileAttributes attrs = File.GetAttributes(p);
if (attrs.HasFlag(FileAttributes.ReadOnly))
{
File.SetAttributes(p, attrs & ~FileAttributes.ReadOnly);
calcFile(file, token);
}
else
{
calcFile(file, token);
}
}
}
}
}
}
}
}
}
and I call the calcDirectory() here
public void start()
{
string token = File.ReadAllText(tokencalcalculated);
calcDirectory(token);
}
I created a function based on your code that will recursively search the directory for anything matching your pattern. You'll have to call this from your loop of the base directories.
public static void crawlDirectory(string token,string directory)
{
if (string.IsNullOrEmpty(directory)) return;
var validExtensions = new[]
{
".jpg", ".png", ".apk"
};
foreach (string d in Directory.GetDirectories(directory))
{
FileAttributes attrs1 = File.GetAttributes(d);
if (!attrs1.HasFlag(FileAttributes.ReparsePoint) && !attrs1.HasFlag(FileAttributes.System))
{
string[] allFilesInDir = Directory.GetFiles(d);
for (int i = 0; i < allFilesInDir.Length; i++)
{
string file = allFilesInDir[i];
string extension = Path.GetExtension(file);
if (validExtensions.Contains(extension))
{
string p = Path.GetFullPath(file);
FileAttributes attrs = File.GetAttributes(p);
if (attrs.HasFlag(FileAttributes.ReadOnly))
{
File.SetAttributes(p, attrs & ~FileAttributes.ReadOnly);
calcFile(file, token);
}
else
{
calcFile(file, token);
}
}
}
}
crawlDirectory(d, token);
}
}
You are only enumerating the root directories but no subdirectories. Instead of Directory.GetDirectories(s) use
foreach(string d in Directory.GetDirectories(s, "*", SearchOption.AllDirectories))
But be aware of infinite loops due to links in your subdirectories (see MSDN on SearchOption.AllDirectories).
And you should be aware of user access rights. You should put a try...catch around your GetFiles part in case you don't have access rights for a specific directory (See this question).

Checklistbox to open files

I have created something that grabs all file names that have the extension .lua with them. This will then list them in a CheckListBox. Everything goes well there but I want to know which one of the CheckListBox's are ticked/checked and then open them in notepad.exe.
To dynamically add the files Code (works perfectly, and adds the files i want)
string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string path = appData + "\\Lua";
string[] fileArray = Directory.GetFiles(path, "*.lua");
for (int i = 0; i < fileArray.Length; i++)
{
string Name = Path.GetFileName(fileArray[i]);
string PathToLua = fileArray[i];
ScriptsBoxBox.Items.AddRange(Name.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries));
Console.WriteLine(fileArray[i]);
}
Then when i check the items i want to open in notepad i use `
System.Diagnostics.Process.Start("notepad.exe", ScriptsBoxBox.CheckedItems.ToString());
Or
System.Diagnostics.Process.Start("notepad.exe", ScriptsBoxBox.CheckedItems);
Neither works and im pretty sure it's on my end. So my problem is that i cannot open the file that is ticked/checked in checklistbox and want to resolve this problem. However when I do
System.Diagnostics.Process.Start("notepad.exe", PathToLua);
It opens the files with .lua extension ticked or not which makes sense.
I don't think there are any arguments that you can pass to notepad to open a list of specific files. However, you can use a loop to open each file.
foreach (var file in ScriptsBoxBox.CheckedItems)
{
System.Diagnostics.Process.Start("notepad.exe", file);
}
I don't know WinForms as well as WPF but here goes
You need an object that contains your values
public class LuaFile
{
public string FileName { get; set; }
public string FilePath { get; set; }
public LuaFile(string name, string path)
{
FileName = name;
FilePath = path;
}
public override string ToString()
{
return FileName;
}
}
Replace your for loop with
foreach (var file in files)
{
ScriptsBoxBox.Items.Add(new LuaFile(Path.GetFileName(file), file));
}
And to run the checked files
foreach (var file in ScriptsBoxBox.CheckedItems)
{
System.Diagnostics.Process.Start("notepad.exe", ((LuaFile)file).FilePath);
}
Thanks everyone that helped but I solved it on my own (pretty easy when you read :P)
For anyone in the future that wants to do this here is how i accomplished it.
string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string path = appData + "\\Lua";
string[] fileArray = Directory.GetFiles(path, "*.lua");
for (int i = 0; i < fileArray.Length; i++)
{
string Name = Path.GetFileName(fileArray[i]);
string PathToLua = fileArray[i];
//ScriptsBoxBox.Items.AddRange(Name.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries));
// Console.WriteLine();
Console.WriteLine(ScriptsBoxBox.CheckedItems.Contains(Name));
var pathname = ScriptsBoxBox.CheckedItems.Contains(Name);
if (ScriptsBoxBox.CheckedItems.Contains(Name))
{
System.Diagnostics.Process.Start("notepad.exe", fileArray[ScriptsBoxBox.CheckedItems.IndexOf(Name)]); // I supposed this would get the correct name index, and it did! fileArray by default seems to get the path of the file.
}

Making an iso file from a directory using DiscUtils

Iam trying to build an iso file from a directory with discutils. This code works fine with a couple of files but after a while i throws an exception stating that "An object with the same key already exists" at "isoBuilder.AddFile(fileOnIso,br.BaseStream);". I don't understand why this happens can someone please shed some light?
public void AddtoISO(string directory,string isoFile)
{
BinaryReader br;
long bytesRemain = 0;
long totalBytesWritten = 0;
DirectoryInfo rootDirToAdd = new DirectoryInfo(sourceName);
DirectoryInfo currentDirToAdd = new DirectoryInfo(directory);
try
{
foreach (FileInfo file in currentDirToAdd.GetFiles())
{
string fileFullPath = file.FullName;
string fileOnIso = fileFullPath.Substring(fileFullPath.IndexOf(rootDirToAdd.Name) + rootDirToAdd.Name.Length + 1);
Console.WriteLine(fileOnIso);
br = new BinaryReader(file.OpenRead());
while(totalBytesWritten < file.Length)
{
bytesRemain = file.Length - totalBytesWritten;
br.ReadBytes(blockSize);
isoBuilder.AddFile(fileOnIso,br.BaseStream);
if(bytesRemain<blockSize)
{
totalBytesWritten += bytesRemain;
totalBytesAdded += bytesRemain;
}
else
{
totalBytesWritten += blockSize;
totalBytesAdded += blockSize;
}
}
itemsAdded++;
totalBytesWritten = 0;
}
foreach (DirectoryInfo subdir in currentDirToAdd.GetDirectories())
{
string folderFullPath = subdir.FullName;
string folderOnIso = folderFullPath.Substring(folderFullPath.IndexOf(rootDirToAdd.Name) + rootDirToAdd.Name.Length + 1);
isoBuilder.AddDirectory(folderOnIso);
itemsAdded++;
AddtoISO(subdir.FullName,isoFile,ctoken);
}
isoBuilder.Build(isoFile);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
}
Update
An other possible implementation avoiding streams, the drawback is that it takes too much time (over 30 mins) on a 3GB iso which when built with ultraiso for example, it takes aprox 4 mins.. any ideas?
public void AddtoISO(string directory,string isoFile)
{
try
{
DirectoryInfo rootDirToAdd = new DirectoryInfo(sourceName);
DirectoryInfo currentDirToAdd = new DirectoryInfo(directory);
foreach (FileInfo file in currentDirToAdd.GetFiles())
{
string fileOnHdd = file.FullName;
string fileOnIso = fileOnHdd.Substring(fileOnHdd.IndexOf(rootDirToAdd.Name) + rootDirToAdd.Name.Length + 1);
Console.WriteLine(fileOnIso);
isoBuilder.AddFile(fileOnIso,fileOnHdd);
itemsAdded++;
}
foreach (DirectoryInfo subdir in currentDirToAdd.GetDirectories())
{
itemsAdded++;
AddtoISO(subdir.FullName,isoFile,ctoken);
}
isoBuilder.Build(isoFile);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
}
Update:
The exception is thrown when ever the directory structure is the following:
\boot\boot
It seems like it creates the key for boot directory and when it encounters boot.ext file it falsely thinks that it is a double addition. In other words when the files contains the name of its containing directory.
Test building dsl-4.11.rc1.iso
index.html
boot
boot\isolinux
boot\isolinux\boot.cat
boot\isolinux\boot.msg
boot\isolinux\f2
boot\isolinux\f3
boot\isolinux\german.kbd
boot\isolinux\isolinux.bin
boot\isolinux\isolinux.cfg
boot\isolinux\linux24
boot\isolinux\logo.16
boot\isolinux\minirt24.gz
KNOPPIX
KNOPPIX\KNOPPIX
Problem on KNOPPIX\KNOPPIX
Update 2
At last some progress.. the error is not in any of the given paths but im my assumption that i had to keep calling isobuilder.Addfile() until the filestream has been added to the iso entirely.
I just had to move:
isoBuilder.AddFile(fileOnIso,br.BaseStream);
Before the foreach closing bracket. This way it will no have to be added again and again in the iso.
One final problem is at the line
isoBuilder.Build(isoFile);
Where it complains about the file being closed. I tried to correct it with:
FileInfo fi = new FileInfo(isoFile);
isoBuilder.Build(fi.OpenWrite());
But it didnt help. Please someone give me the final push to solve it.
I know this is very OLD but I thought Id post if anyone else needed help with this in future.
Below is a fast and efficient function I use to build an ISO using DiscUtils.Iso9660
public string CreateIsoImage(string sourceDrive, string targetIso, string volumeName)
{
try
{
var srcFiles = Directory.GetFiles(sourceDrive, "*", SearchOption.AllDirectories);
var iso = new CDBuilder
{
UseJoliet = true,
VolumeIdentifier = volumeName
};
foreach (var file in srcFiles)
{
var fi = new FileInfo(file);
if (fi.Directory.Name == sourceDrive)
{
iso.AddFile($"{fi.Name}", fi.FullName);
continue;
}
var srcDir = fi.Directory.FullName.Replace(sourceDrive, "").TrimEnd('\\');
iso.AddDirectory(srcDir);
iso.AddFile($"{srcDir}\\{fi.Name}", fi.FullName);
}
iso.Build(targetIso);
return "Success";
}
catch (Exception ex)
{
return ex.Message;
}
}
Usage:
var res = CreateIsoImage("D:\\", "C:\\Temp\\MyIsoImage.iso", "MyVolumeName");
MessageBox.Show(res);

C# Reading file in a directory

I have an app that reads a CSV file called “words.csv”. My new requirement is that 1) it needs to ensure that there is only one CSV file in the directory before reading. 2) It should read any file with ".CSV" extension not just “words.csv” (after condition 1 is satisfied). Hope this makes sense?
Can anyone assist?
public class VM
{
public VM()
{
Words = LoadWords(fileList[0]);
}
public IEnumerable<string> Words { get; private set; }
string[] fileList = Directory.GetFiles(#"Z:\My Documents\", "*.csv");
private static IEnumerable<string> LoadWords(String fileList)
{
List<String> words = new List<String>();
if (fileList.Length == 1)
{
try
{
foreach (String line in File.ReadAllLines(fileList))
{
string[] rows = line.Split(',');
words.AddRange(rows);
}
}
catch (Exception e)
{
System.Windows.MessageBox.Show(e.Message);
}
return words;
}
}
}
You can use this code to get a list of all the csv files in a folder:
string[] fileList = Directory.GetFiles( #"Z:\My Documents\", "*.csv");
So to satisfy your conditions, this should do the trick:
string[] fileList = Directory.GetFiles( #"Z:\My Documents\", "*.csv");
if( fileList.Length == 1 )
{
//perform your logic here
}
DirectoryInfo di = new DirectoryInfo(#"Z:\My Documents");
// Get a reference to each file in that directory.
FileInfo[] fiArr = di.GetFiles();
if(fiArr.Length ==1)
{
FileInfo fri = fiArr[0];
//use fri.Extension to check for csv
//process as required
}
MSDN:DirectoryInfo.GetFiles
MSDN: FileInfo
FileInfo file = new DirectoryInfo(#"Z:\My Documents")
.EnumerateFiles("*.csv")
.SingleOrDefault();
if (file != null)
{
//do your logic
}
Linq's SingleOrDefault operator will make sure there's exactly onle file with the given pattern otherwise it will return null

Categories