Here is my code:
private static bool checkifDirectoryContainsFilesWithSpecifiedExtention(string path, string fileExestention) //Like C:\\smth, *.html
{
foreach (string f in Directory.GetFiles(path,fileExestention))
{
return true;
}
foreach (string d in Directory.GetDirectories(path))
{
return checkifDirectoryContainsFilesWithSpecifiedExtention(d,fileExestention);
}
return false;
}
In this function the program returns every file with specified extention BUT If I contain only one file with the specified extention in the last folder, the function returns false, which makes no sence because it exists
My question is why it does that...
Try it out. I can't really find the bug.
The problem is the "return" inside the foreach (string d in Directory.GetDirectories(path)) loop. It will only check the first directory per level. You need something like this (not nice, but keeping your style/format)
bool ok = false;
foreach (string d in Directory.GetDirectories(path))
{
ok = ok || checkifDirectoryContainsFilesWithSpecifiedExtention(d,
fileExestention);
}
return ok;
Better yet, use the linq that Marc provided.
Turned this into a LINQ query
private static bool CheckifDirectoryContainsFilesWithSpecifiedExtention(string path, string fileExestention)
//Like C:\\smth, *.html
{
return Directory.GetFiles(path, fileExestention).Any() ||
Directory.GetDirectories(path)
.Select(d => CheckifDirectoryContainsFilesWithSpecifiedExtention(d, fileExestention))
.FirstOrDefault();
}
Tried it on the a few debug folders using *.exe as the mask and it returns true. It traverses sub folders as well. Not sure what you meant by one file in the last folder.
See if it works for you.
this works for me
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StackOverflowSnippets
{
class Program
{
static void Main(string[] args)
{
String path = #"C:\smth"; String pattern = "*.html";
Console.WriteLine("__" + checkifDirectoryContainsFilesWithSpecifiedExtention(path, pattern));
Console.ReadLine();
}
private static bool checkifDirectoryContainsFilesWithSpecifiedExtention(string path, string fileExestention) //Like C:\\smth, *.html
{
foreach (string f in Directory.GetFiles(path, fileExestention))
{
return true;
}
foreach (string d in Directory.GetDirectories(path))
{
if (checkifDirectoryContainsFilesWithSpecifiedExtention(Path.Combine(path, d), fileExestention))
{
return true;
}
}
return false;
}
}
}
Related
I have a large directory of folders and files that contain a space at the end of the name, I'm trying to rename the directories with that space to one without, so that another application would be able to access it.
I'm using C# (but if there's a better option that would fix that issue please suggest) and here's my entire code:
using System;
using System.IO;
using System.Text.RegularExpressions;
namespace removing_spaces_in_directories_names
{
class Program
{
public static string path = "../../../old_directory";
static void Main(string[] args)
{
DirectoryInfo di = new DirectoryInfo(path);
WalkDirectoryTree(di);
Console.ReadLine();
}
static void WalkDirectoryTree(System.IO.DirectoryInfo root)
{
if (root.Name != "old_directory")
{ renameDirectory(root); }
DirectoryInfo[] diArr = root.GetDirectories();
foreach(DirectoryInfo di in diArr)
{
WalkDirectoryTree(di);
}
}
static void renameDirectory(System.IO.DirectoryInfo dir)
{
Console.WriteLine("renaming: " + dir.FullName);
string newName = ReplaceLastOccurrence(dir.FullName, " ", "");
if (Directory.Exists(dir.FullName) == false)
{
//dir.MoveTo(newName);
String oldName = #"\\?\"+dir.FullName;
Directory.Move(oldName,newName);
}
}
public static string ReplaceLastOccurrence(string Source, string Find, string Replace)
{
int place = Source.LastIndexOf(Find);
if (place == -1)
return Source;
string result = Source.Remove(place, Find.Length).Insert(place, Replace);
return result;
}
}
}
I have tried adding "\?\" to the beginning of the folder name as suggested here but that's not working, the error I'd get if I add it is: Illeagal characters in path.
On the other hand if I use dir.MoveTo(newName); without the "\?\" characters I'd get the error: Could not find a part of the path 'Volunteer Information '
How can I go through this if at all? would perhaps running this application on linux rather than windows help?
For each directory that you want to rename (remove the trailing space at the end in this case), let's say your DirectoryInfo variable is called di
You want to do this:
string oldName = di.FullName;
string newName = oldName.TrimEnd();
Directory.Move(oldName, newName);
I rewrote this in a PHP application that's sitting on linux and it worked.
Just learning RX and wanted to make a program that iterated the file system. Here is what I came up with that works:
using System;
using System.IO;
using System.Reactive.Disposables;
using System.Reactive.Linq;
namespace ConsoleApplication8
{
internal class Program
{
private static IObservable<string> GetFiles(string folder, string filePattern)
{
return Observable.Create<string>(
o =>
{
var files = Directory.GetFiles(folder, filePattern);
foreach (var file in files)
{
o.OnNext(file);
}
var folders = Directory.GetDirectories(folder);
foreach (var f in folders)
{
var x = GetFiles(f, filePattern);
x.Subscribe(p => { o.OnNext(p); });
}
o.OnCompleted();
return Disposable.Empty;
});
}
private static void Main(string[] args)
{
var o = GetFiles(#"d:\temp", "*.*");
o.Subscribe(p => { Console.WriteLine(p); });
Console.Read();
}
}
}
(Note the use of recursion by calling GetFiles again and subscribing)
While it works it seems very clumsy, I can't help thinking that I should be using something like Concat to combine the sequences instead of just bubbling them back up.
Also I would like to change that Foreach to a Parallel.ForEach but I'm unsure the ramifications this would have using RX. I can't seem to find much for documentation.
Any tips on how to write this better using RX?
To solve a problem like this, it can help to write a LINQ version of the function first. eg:
static IEnumerable<string> GetFiles(string folder, string filePattern)
{
return Directory.GetFiles(folder, filePattern)
.Concat(Directory.GetDirectories(folder).SelectMany(f => GetFilesEnumerable(f, filePattern)));
}
Then just change the IEnumerables to IObservables:
static IObservable<string> GetFiles(string folder, string filePattern)
{
return Directory.GetFiles(folder, filePattern).ToObservable()
.Concat(Directory.GetDirectories(folder).ToObservable().SelectMany(f => GetFilesEnumerable(f, filePattern)));
}
Turns out, based on my discovery of SearchOption.AllDirectories (why in all my years have I never noticed this) it can be boiled down into two real lines of code:
using System;
using System.IO;
using System.Reactive.Linq;
namespace ConsoleApplication8
{
internal class Program
{
private static void Main(string[] args)
{
var o = Directory.GetFiles(#"e:\code", "*.*", SearchOption.AllDirectories).ToObservable();
o.Subscribe(f => Console.WriteLine(f));
Console.Read();
}
}
}
Crazy how simple it really is now. Need a new RX problem to play with.
my project is about recording screen as sequence of images then instead of make it as video i planed to load all image directories to list and use timer to view them image by image, but i get files in wrong order like this:
this code is to load files from directory:
string[] array1 = Directory.GetFiles("C:\\Secret\\" + label1.Text, "*.Jpeg");
Array.Sort(array1);
foreach (string name in array1)
{
listBox1.Items.Add(name);
}
timer2.Start();
this code to view them
int x = 0;
private void timer2_Tick(object sender, EventArgs e)
{
if (x >= listBox1.Items.Count)
{
timer2.Stop();
}
else
{
ssWithMouseViewer.Image = Image.FromFile(listBox1.Items[x].ToString());
x++;
}
}
i need to view them in order like 0.jpeg, 1.jpeg, 2.jpeg.....10.jpeg, 11..jpeg...
The strings are sorted: in lexicographic order...
you have two options: rename the files so they be ordered in lexicographic order (eg: 001, 002, 003...), or, using linq, and file name manipulations:
IEnumerable<string> sorted = from filename in array1
orderby int.Parse(Path.GetFileNameWithoutExtension(filename))
select filename;
Presumably your array should already be sorted as you enter label1.text in numerical order? If not it might be easier for you to sort the label1.text values into numerical order before calling your method.
You need to use a "natural sort order" comparer when sorting the array of strings.
The easiest way to do this is to use P/Invoke to call the Windows built-in one, StrCmpLogicalW(), like so (this is a compilable Console application):
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security;
namespace ConsoleApp1
{
[SuppressUnmanagedCodeSecurity]
internal static class NativeMethods
{
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
public static extern int StrCmpLogicalW(string psz1, string psz2);
}
public sealed class NaturalStringComparer: IComparer<string>
{
public int Compare(string a, string b)
{
return NativeMethods.StrCmpLogicalW(a, b);
}
}
sealed class Program
{
void run()
{
string[] filenames =
{
"0.jpeg",
"1.jpeg",
"10.jpeg",
"11.jpeg",
"2.jpeg",
"20.jpeg",
"21.jpeg"
};
Array.Sort(filenames); // Sorts in the wrong order.
foreach (var filename in filenames)
Console.WriteLine(filename);
Console.WriteLine("\n");
Array.Sort(filenames, new NaturalStringComparer()); // Sorts correctly.
foreach (var filename in filenames)
Console.WriteLine(filename);
}
static void Main(string[] args)
{
new Program().run();
}
}
}
NOTE: This example is based on code from this original answer.
The most simple way is to use the OrderBy function in LINQ in combination with Path.GetFileNameWithoutExtension like so:
string[] array1 = Directory.GetFiles("C:\\Secret\\" + label1.Text, "*.Jpeg");
array1 = array1.OrderBy(x => int.Parse(System.IO.Path.GetFileNameWithoutExtension(x))).ToArray();
To use the OrderBy function, you need to add a using statement for the namespace System.Linq;
So I'm trying to run through every file on my harddrive, but it stops once it gets to the 2115th (I think) loop. I believe it is a stack overflow due to my use of recursion, but I'm new to C# and really have no idea. Here's my code, thank you very much.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Data;
namespace test_data
{
class Program
{
static string drive = Path.GetPathRoot(Environment.CurrentDirectory);
static void CrawlDir(string dir)
{
string[] dir_package = {};
List<string> dir_list = new List<string>();
foreach (string scan_dir in Directory.GetDirectories(dir))
{
try
{
dir_list.Add(scan_dir);
}
catch (System.Exception error)
{
Console.WriteLine(error.Message);
}
}
dir_package = dir_list.ToArray();
Process_Package(dir_package);
}
static void Main(string[] args)
{
CrawlDir(drive);
Console.ReadLine();
}
static void Process_Package(string[] package)
{
foreach (string dir in package)
{
Console.WriteLine(dir);
try
{
CrawlDir(dir);
}
catch (Exception)
{
Console.WriteLine("Error!");
}
}
}
}
}
Just use what's built in - Directory.GetDirectories supports an optional parameter to specify if you want to get all directories recursively:
var dirs = Directory.GetDirectories(drive, "*.*", SearchOption.AllDirectories);
Note that this is a blocking call - instead you could use Directory.EnumerateDirectories to receive the directory names one by one as they are being found:
var dirs = Directory.EnumerateDirectories(drive, "*.*", SearchOption.AllDirectories);
foreach(string dir in dirs)
{
Console.WriteLine(dir);
}
Use this overload with SearchOption.AllDirectories so you don't have to do any recursion:
public static string[] GetDirectories(
string path,
string searchPattern,
SearchOption searchOption
)
Recursion looks more or less ok, although you do not really need a list in CrawlDir. If you had a stack overflow you'd get a nasty message.
My guess is - the program completes and stops at ReadLine() waiting for you to press Enter.
You're adding a lot of overhead to each level of recursion by using a List (dir_list), an array (dir_package) and two try/catch loops. I don't know what you're really trying to do, but for this example it's way overkill.
Still, it would take a lot to cause a stack overflow on a modern OS. What error message are you getting?
This code should be equivalent.
using System;
using System.IO;
namespace test_data
{
class Program
{
static string drive = Path.GetPathRoot(Environment.CurrentDirectory);
static void CrawlDir(string dir)
{
foreach (string subDir in Directory.GetDirectories(dir))
{
try
{
Console.WriteLine(subDir);
CrawlDir(subDir);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
static void Main(string[] args)
{
CrawlDir(drive);
Console.ReadLine();
}
}
}
I am very new to C# and i have written the following class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace PrinterManager
{
class CheckFilesExist
{
public class CheckFilesExist
{
public static bool check(bool isThere)
{
DirectoryInfo di = new DirectoryInfo("c:\temp");
FileInfo[] TXTFiles = di.GetFiles("*.xml");
if (TXTFiles.Length == 0)
{
return isThere;
}
foreach (var fi in TXTFiles)
//return (fi.Exists);
return (fi.Exists);
return check;
}
}
}
}
It should check the directory for *.xml files and add them to an array. If it doesnt find any files then it should return false. It will go through the array and return true or false based on "check".
But i am getting the following error:
Cannot convert method group 'check' to non-delegate type 'bool'. Did
you intend to invoke the method?
It doesnt seem to like, "return check;" at the end.
I basically want to return a check to see if files exists in the folder.
Any ideas why mine isnt working?
Thanks
You can make a one-liner out of your method:
return new DirectoryInfo(#"c:\temp").EnumerateFiles("*.xml").Any();
Note that you are either have to use a literal string (prefixed by #) or properly escape the directory name, i.e. "C:\\temp".
No, it doesn't like return check; at the end - what did you want it to do? Your method is check - so "return true or false based on check" doesn't really make sense. Did you actually mean to return isThere instead?
It's not clear what the parameter is even really meant to be there for, to be honest... and if you've asked a DirectoryInfo for the files in that directory, I'd personally expect them to exist - otherwise why would they be returned?
Oh, and your directory name contains a tab where I suspect you actually want a backslash followed by a t.
I suspect your method would be better as:
public static bool TempDirectoryContainsXmlFiles()
{
DirectoryInfo di = new DirectoryInfo(#"c:\temp");
return di.GetFiles("*.xml").Length > 0;
}
or using LINQ for clarity:
public static bool TempDirectoryContainsXmlFiles()
{
DirectoryInfo di = new DirectoryInfo(#"c:\temp");
return di.GetFiles("*.xml").Any();
}
(You can use EnumerateFiles as shown by BrokenGlass which is more efficient for a large directory, but it's only available in .NET 4 and upwards.)
At a first glance, the problem as to be with the fact of your "check" variable having the same name as your function...
try like this....
private static bool Check_file_Existence(string sFileName)
{
try
{
return File.Exists(sFileName);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
}