I have a program that a button, when clicked, executes a sound located in my download folder. My question is how to execute the sound on another computer if the path for finding it is different.
You need the path to a file to run it. If you don't have the path - you have to search for it.
Pick a base directory where you think the file is. If you don't know where - that will be the whole drive.
Write a recursive function that would search said folder recursively.
Test each file by what ever your search condition is, i.e. file name, file hash, etc.
For example:
string SearchForFile(string searchPath, Func<string, bool> searchPredicate)
{
try
{
foreach (string fileName in Directory.EnumerateFiles(searchPath))
{
if (searchPredicate(fileName))
{
return fileName;
}
}
foreach (string dirName in Directory.EnumerateDirectories(searchPath))
{
var childResult = SearchForFile(dirName, searchPredicate);
if (childResult != null)
{
return childResult;
}
}
return null;
}
catch (UnauthorizedAccessException)
{
return null;
}
}
Usage:
var filePath = SearchForFile(#"C:\", x => Path.GetFileName(x) == "yourFileName.mp3");
Related
I'm doing a console project whose goal is to search the entire disk for all files with the extension '.config'
I've tried something like:
foreach (string file in Directory.GetFiles("C:\\", "*.config", SearchOption.AllDirectories))
{
Console.WriteLine(file);
Console.ReadLine();
}
but gave me an error "denied access to path (...)".
On the internet I found this code:
Stack<string> pending = new Stack<string>();
pending.Push("C:\\");
while (pending.Count != 0)
{
var path = pending.Pop();
string[] next = null;
try
{
next = Directory.GetFiles(path, "*.config");
}
catch { }
if (next != null && next.Length != 0)
foreach (var file in next)
{
Console.WriteLine(file);
Console.ReadLine();
}
try
{
next = Directory.GetDirectories(path);
foreach (var subdir in next) pending.Push(subdir);
}
catch { }
}
but it just shows the path clicking always in 'enter' and I want to save those files/path in a list.
Someone can help?
There are two things you can do to improve that code:
Use Directory.EnumerateFiles() and Directory.EnumerateDirectories() to avoid making a copy of the names of all the files in each directory.
Make the return type of the method IEnumerable<string> to make it easier to consume.
We also need to be very careful about exceptions caused by attempting to access protected files and directories. The code below is also complicated by the fact that you're not allowed to yield return from inside a try/catch block, so we have to rearrange the code somewhat.
(Also note that we have to dispose the enumerator returned from .GetEnumerator(); normally this is done automatically when you use foreach, but in this case we can't - because of having to avoid doing yield return in a try/catch - so we have to use using to dispose it.)
Here's a modification of your original code to do this:
public static IEnumerable<string> GetFiles(string root, string spec)
{
var pending = new Stack<string>(new []{root});
while (pending.Count > 0)
{
var path = pending.Pop();
IEnumerator<string> fileIterator = null;
try
{
fileIterator = Directory.EnumerateFiles(path, spec).GetEnumerator();
}
catch {}
if (fileIterator != null)
{
using (fileIterator)
{
while (true)
{
try
{
if (!fileIterator.MoveNext()) // Throws if file is not accessible.
break;
}
catch { break; }
yield return fileIterator.Current;
}
}
}
IEnumerator<string> dirIterator = null;
try
{
dirIterator = Directory.EnumerateDirectories(path).GetEnumerator();
}
catch {}
if (dirIterator != null)
{
using (dirIterator)
{
while (true)
{
try
{
if (!dirIterator.MoveNext()) // Throws if directory is not accessible.
break;
}
catch { break; }
pending.Push(dirIterator.Current);
}
}
}
}
}
As an example, here's how you could use a console app to list all the accessible ".txt" files on the "C:\" drive:
static void Main()
{
foreach (var file in GetFiles("C:\\", "*.txt"))
{
Console.WriteLine(file);
}
}
Replace the lines
Console.WriteLine(file);
Console.ReadLine();
with a method to store them in a list.
For example
foundFiles.Add(file);
Then when the method is done, you can read all found file paths from this list.
Notes:
This will not yield all files on the system that match the filter.
Only files where your application has access to their respective directory are found this way.
For example the Windows directory and user directories of other users are usually protected. (assuming you run on Windows)
Keep in mind, that some files might be protected independently of their directory.
So when trying to read them, also consider the fact, that the read might fail.
Just encompass the read with a try catch.
Regarding the error "denied access to path (...)", sometimes you have to run Visual Studio as an a administrator in order to access some folders in the C:\ drive.
I need help, because I've written a method that should find a special directory on a computer that definitely exists.
First I've written a method that will be go through every drive on a computer and open up for every drive the recursive method.
private string LocateOnDrives()
{
string result = string.Empty;
string[] drives = Directory.GetLogicalDrives();
foreach (string drive in drives)
{
string buffer = this.Locate(drive);
if (buffer.EndsWith(SEARCH_PATTERN))
{
return buffer;
}
}
return result;
}
And this is the method that is called for every drive:
private string Locate(string directory)
{
string result = string.Empty;
try
{
string[] dirs = Directory.GetDirectories(directory);
foreach (string dir in dirs)
{
if (dir.EndsWith(SEARCH_PATTERN))
{
return dir;
}
else
{
result = this.Locate(dir);
}
}
}
catch { }
return result;
}
The try catch is necessary, because there are some directories with no permission. I have the permission for the sought folder and when i debug this, it will jump into the if condition that it has found and set the local 'result' to this sought folder. Up to this point it really makes that what was my intention. But the recursive method will search further and the overall return is string.Empty!
I already did something link this:
private string tragetDir;
private string Locate(string directory)
{
string result = string.Empty;
try
{
string[] dirs = Directory.GetDirectories(directory);
foreach (string dir in dirs)
{
if (dir.EndsWith(DEFAULT_GTAV_DIRECTORY_NAME))
{
targetDir = dir;
}
else
{
result = this.Locate(dir);
}
}
}
catch { }
return result;
This is working for me, but not what I wanted to have, because it should be possible that the recursive method will return this wanted folder…
It is late for me and I just want to fix this little mistake!
Can someone help me out, because I am desperate, THANKS!
When you find a match and return it, then unwind once in your nested calls to Locate(), you assign the match to result but then keep progressing with the loop, when you actually want to break out of it.
result = this.Locate(dir, SEARCH_PATTERN);
if (result.EndsWith(SEARCH_PATTERN))
{
break;
}
Also, you might consider just catching the UnauthorizedAccessException since that's the one it'll throw if you don't have permission to a particular directory.
This is a solution I tried and it worked for me now:
private string Locate(string directory)
{
string result = string.Empty;
string[] dirs = new string[0];
try
{
dirs = Directory.GetDirectories(directory);
}
catch { /* Ignore */ }
foreach (string dir in dirs)
{
if (dir.EndsWith(SEARCH_PATTERN))
{
result = dir;
break;
}
else
{
result = this.Locate(dir);
if (result.EndsWith(SEARCH_PATTERN))
{
break;
}
}
}
return result;
}
First I had to check if the current "dir" in the loop was already the sought folder. If not, the loop had to browse inside this folder and if the result inside this folder isn't the sought folder the loop had to going on and search on or in the next folder in loop.
In any case that the right directory was found, the loop will "break" and return the result!
This is it!
I'd like my program to scan the user's hard drive for java.exe.
I was considering using a for-loop and then going through each directory and then check if the directory names match the ones I would set up and then check in those for the java exe, but I'm sure there is a much more efficient way of doing so.
Any ideas on how to approach this?
Edit:
I've gone ahead and done some foreach loops, but it isn't going too well. I'm probably missing something:
// Scan for Java executable (java.exe)
foreach (String dir in Directory.GetDirectories("C:/"))
{
if (dir == "Program Files")
{
foreach (String _dir in Directory.GetDirectories(dir)) {
if (_dir == "Java")
{
foreach (String javaDir in Directory.GetDirectories(_dir))
{
if (javaDir == "jre7")
{
foreach (String binDir in Directory.GetDirectories(javaDir)) {
if (binDir == "bin")
{
foreach (String file in Directory.GetFiles(binDir))
{
if (file == "java.exe")
{
javaExe = file;
}
}
}
}
}
}
}
}
}
}
You are looking for java.exe. So
Firstly you should look for directory where oracle always install it's java.exe
which should be at
C:\Windows\System32
to limit your search and then search in other directories.
var paths = new List<string>
{
Environment.SystemDirectory,
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)+#"\java",
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86)+#"\java",
Environment.GetFolderPath(Environment.SpecialFolder.Programs)+#"\java"
//C:\
//rest
};
foreach (string path in paths)
{
var ser = Search("java.exe", path);
if (!string.IsNullOrEmpty(ser))
{
if (File.Exists(ser))
{
javaExe = ser;
break;
}
}
}
Search function:
private static string Search(string pattern, string root)
{
if (!Directory.Exists(root))
{
return string.Empty;
}
var paths = new Queue<string>();
paths.Enqueue(root);
while (paths.Count > 0)
{
root = paths.Dequeue();
string[] temp = Directory.GetFiles(root, pattern);
foreach (string t in temp)
{
return t;
}
temp = Directory.GetDirectories(root);
foreach (string t in temp)
{
paths.Enqueue(t);
}
}
return string.Empty;
}
Also it's preferred to use this search method to avoid Access permissions.
Note:
You could find java.exe in more than one place.
Do you only want to see if java.exe is there?
File.Exists(#"C:\Program Files\Java\jre7\bin\java.exe")
You might need additional logic to look in the Program Files (x86) folder if needed. Also this will obviously fail if the user installed java somewhere else.
If you want to know where is java, take a look at this other Stack Overflow post.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
UnauthorizedAccessException cannot resolve Directory.GetFiles failure
This is the function im using to search the files:
public string SearchFor(string fileExtension, DirectoryInfo at)
{
string error = null;
try
{
foreach (DirectoryInfo subDir in at.GetDirectories())
{
SearchFor(fileExtension, subDir);
foreach (FileInfo f in at.GetFiles())
{
// test f.name for a match with fileExtension
// if it matches...
// yield return f.name;
if (f.Name == fileExtension)
{
return f.Name;
}
else
{
error = f.Name;
}
}
}
}
catch (UnauthorizedAccessException) { }
return error;
}
I know what to put for path when calling the function but what should i put for files ? How to use/call the function ? Im not sure what to put as for files .
One option is to run the program as administrator. (right click and run-as-administrator)
Another option is to custom code your own directory search, something like:
public IEnumerator SearchFor(string fileExtension, DirectoryInfo at) {
try {
foreach (DirectoryInfo subDir in at.GetDirectories()) {
SearchFor(fileExtension, subDir);
foreach (FileInfo f in at.GetFiles()) {
// test f.name for a match with fileExtension
// if it matches...
// yield return f.name;
}
}
} catch (UnauthroizedAccessException) { }
}
If the windows account under which you are running the function does not have permission to change directory into a folder, you will get that exception if you try to access it from code. You can either handle it gracefully with a try / catch and continue the search, or you can try running under an account that has permissions to descend into that directory.
Imagine I wish to create (or overwrite) the following file :- C:\Temp\Bar\Foo\Test.txt
Using the File.Create(..) method, this can do it.
BUT, if I don't have either one of the following folders (from that example path, above)
Temp
Bar
Foo
then I get an DirectoryNotFoundException thrown.
So .. given a path, how can we recursively create all the folders necessary to create the file .. for that path? If Temp or Bar folders exists, but Foo doesn't... then that is created also.
For simplicity, lets assume there's no Security concerns -- all permissions are fine, etc.
To summarize what has been commented in other answers:
//path = #"C:\Temp\Bar\Foo\Test.txt";
Directory.CreateDirectory(Path.GetDirectoryName(path));
Directory.CreateDirectory will create the directories recursively and if the directory already exist it will return without an error.
If there happened to be a file Foo at C:\Temp\Bar\Foo an exception will be thrown.
DirectoryInfo di = Directory.CreateDirectory(path);
Console.WriteLine("The directory was created successfully at {0}.",
Directory.GetCreationTime(path));
See this MSDN page.
Use Directory.CreateDirectory before you create the file. It creates the folder recursively for you.
. given a path, how can we recursively create all the folders necessary to create the file .. for that path
Creates all directories and subdirectories as specified by path.
Directory.CreateDirectory(path);
then you may create a file.
You will need to check both parts of the path (directory and filename) and create each if it does not exist.
Use File.Exists and Directory.Exists to find out whether they exist. Directory.CreateDirectory will create the whole path for you, so you only ever need to call that once if the directory does not exist, then simply create the file.
You should use Directory.CreateDirectory.
http://msdn.microsoft.com/en-us/library/54a0at6s.aspx
Assuming that your assembly/exe has FileIO permission is itself, well is not right. Your application may not run with admin rights. Its important to consider Code Access Security and requesting permissions
Sample code:
FileIOPermission f2 = new FileIOPermission(FileIOPermissionAccess.Read, "C:\\test_r");
f2.AddPathList(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, "C:\\example\\out.txt");
try
{
f2.Demand();
}
catch (SecurityException s)
{
Console.WriteLine(s.Message);
}
Understanding .NET Code Access Security
Is “Code Access Security” of any real world use?
You want Directory.CreateDirectory()
Here is a class I use (converted to C#) that if you pass it a source directory and a destination it will copy all of the files and sub-folders of that directory to your destination:
using System.IO;
public class copyTemplateFiles
{
public static bool Copy(string Source, string destination)
{
try {
string[] Files = null;
if (destination[destination.Length - 1] != Path.DirectorySeparatorChar) {
destination += Path.DirectorySeparatorChar;
}
if (!Directory.Exists(destination)) {
Directory.CreateDirectory(destination);
}
Files = Directory.GetFileSystemEntries(Source);
foreach (string Element in Files) {
// Sub directories
if (Directory.Exists(Element)) {
copyDirectory(Element, destination + Path.GetFileName(Element));
} else {
// Files in directory
File.Copy(Element, destination + Path.GetFileName(Element), true);
}
}
} catch (Exception ex) {
return false;
}
return true;
}
private static void copyDirectory(string Source, string destination)
{
string[] Files = null;
if (destination[destination.Length - 1] != Path.DirectorySeparatorChar) {
destination += Path.DirectorySeparatorChar;
}
if (!Directory.Exists(destination)) {
Directory.CreateDirectory(destination);
}
Files = Directory.GetFileSystemEntries(Source);
foreach (string Element in Files) {
// Sub directories
if (Directory.Exists(Element)) {
copyDirectory(Element, destination + Path.GetFileName(Element));
} else {
// Files in directory
File.Copy(Element, destination + Path.GetFileName(Element), true);
}
}
}
}
Following code will create directories (if not exists) & then copy files.
// using System.IO;
// for ex. if you want to copy files from D:\A\ to D:\B\
foreach (var f in Directory.GetFiles(#"D:\A\", "*.*", SearchOption.AllDirectories))
{
var fi = new FileInfo(f);
var di = new DirectoryInfo(fi.DirectoryName);
// you can filter files here
if (fi.Name.Contains("FILTER")
{
if (!Directory.Exists(di.FullName.Replace("A", "B"))
{
Directory.CreateDirectory(di.FullName.Replace("A", "B"));
File.Copy(fi.FullName, fi.FullName.Replace("A", "B"));
}
}
}