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();
}
}
}
Related
I want to make a program in C# that replaces the text of all files in a folder.
I tried this:
using System;
using System.IO;
namespace Stackoverflow
{
class Program
{
static void Main(string[] args)
{
String[] files = Directory.GetFiles(#"C:\Users\test\folder", "*", SearchOption.AllDirectories);
File.WriteAllText(files, "Test");
}
}
}
But I get an error that says that it cannot be converted from "string[]" to "string"
Does anyone know how to solve this?
Instead of
File.WriteAllText(files, "Test");
try using
files.ForEach(file => File.WriteAllText(file, "Test"));
This should work.
EDIT: Or as Heinzi commented, you can similarly solve it in a loop instead of a lambda expression:
foreach (string file in files)
{
File.WriteAllText(file, "Test");
}
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;
}
}
}
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.
I would like my program to read sub-folders from folder in my solution, but i don't know how to read folder names. I can only find, how to read file names and this is not hard to get to work, but with folders, this doesn't seem to work the same way.
Basically I want to load from "Paevik" (2) sub-folders.
E: I forgot to mention, that I want that list into my comboBox
There is System.IO.Directory.EnumerateDirectories(string Path)-method. It returns a collections with directories. Example:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
class Program
{
private static void Main(string[] args)
{
try
{
string dirPath = #"\\archives\2009\reports";
List<string> dirs = new List<string>(Directory.EnumerateDirectories(dirPath));
foreach (var dir in dirs)
{
Console.WriteLine("{0}", dir.Substring(dir.LastIndexOf("\\") + 1));
}
Console.WriteLine("{0} directories found.", dirs.Count);
}
catch (UnauthorizedAccessException UAEx)
{
Console.WriteLine(UAEx.Message);
}
catch (PathTooLongException PathEx)
{
Console.WriteLine(PathEx.Message);
}
}
}
See MSDN.
Try DirectoryInfo.EnumerateDirectories Method
http://msdn.microsoft.com/en-us/library/dd413235.aspx
You can use "GetDirectories" to retrieve an array containing full names of all subdirectories.
string[] subdirectories = Directory.GetDirectories("Full path of your parent folder");
See sample on MSDN page.
i want to know how i can test if i can access a string path or not. Here is the code I use:
using System;
using System.IO;
namescpace prog1
{
class Program
{
static void Main(string[] args)
{
string path = #"C:\Users\Admin";
DirectoryInfo dir = new DirectoryInfo(path);
foreach (FileInfo fil in dir.GetFiles())
{
//At dir.GetFiles, I get an error saying
//access to the string path is denied.
Console.WriteLine(fil.Name);
}
Console.ReadLine();
}
}
}
I want to test if acces is denied (to string path)
Then do the GetFiles and all that.
I've already found this: how can you easily check if access is denied for a file in .NET?
Any help?
The simplest (and usually safest) option is to just do what you're doing now, but wrap the code in proper exception handling.
You can then catch the UnauthorizedAccessException from GetFiles (and potentially a SecurityException from the DirectoryInfo constructor, depending on the path) explicitly, and put your handling logic there.
Can do something like this:
static void Main(string[] args)
{
string path = #"C:\Users\Admin";
DirectoryInfo dir = new DirectoryInfo(path);
FileInfo[] files = null;
try {
files = dir.GetFiles();
}
catch (UnauthorizedAccessException ex) {
// do something and return
return;
}
//else continue
foreach (FileInfo fil in files )
{
//At dir.GetFiles, I get an error saying
//access to the string path is denied.
Console.WriteLine(fil.Name);
}
Console.ReadLine();
}