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.
Related
I have a program written in C# which lists all files in all directories except that ones where you need admin rights. It has no errors but always gives me an access denied exception for a directory that I already ignore. The access denied exception is for "C:$Recycle.Bin\S-1-5-18".
Actually, I ignrore this directory AND run the program with admin rights but the exception is still here.Can anyone help me? Thanks
static void List()
{
List<string> files = new List<string>();
List<string> nofiles = new List<string>();
foreach (var drives in DriveInfo.GetDrives())
{
var filez = Directory.GetFiles(drives.Name,"*",SearchOption.AllDirectories);
foreach (string f in filez)
{
if (f.StartsWith(#"C:\Windows"))
{
}
else if (f.StartsWith(#"C:\Config.Msi"))
{
}
else if (f.StartsWith(#"C:\Program Files"))
{
}
else if (f.StartsWith(#"C:\Program Files (x86)"))
{
}
else if (f.StartsWith(#"C:\DumpStack.log"))
{
}
else if(f.StartsWith(#"C:\$Recycle.Bin\S-1-5-18"))
{
}
else if(f.StartsWith(#"C:\Documents and Settings"))
{
}
else
{
files.Add(f);
}
}
foreach (string fl in files)
{
var c = Path.GetFullPath(fl);
Console.WriteLine(c);
Console.ReadKey();
}
Console.ReadKey();
}
}
Direct access almost always ends with access denied somewhere you should specify the search rules more precisely with the enumeration options, like below:
foreach (var drive in DriveInfo.GetDrives())
{
if (drive.IsReady == false)
{
continue;
}
var filez = Directory.GetFiles(drive.Name, "*", new EnumerationOptions
{
AttributesToSkip = FileAttributes.Hidden | FileAttributes.System,
IgnoreInaccessible = true,
RecurseSubdirectories = true,
ReturnSpecialDirectories = true,
});
// TODO: implement the rest of your code hier ...
}
where the FileAttributes.Hidden is not realy required.
... hope that helps!
With Directory.GetFiles(drives.Name,"*",SearchOption.AllDirectories); you already iterate trough all the directories. The filtering is done afterwards and only used to decide whether you add the directory name (that you already have!) to your list.
To filter the way you want, you need to implement the recursion yourself and catch the exception on each step.
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!
directory is a path, ie L:\\H435431 Project Name which may or may not contain a sub directory named 2-Storage, or 2-STORAGE. If this directory is discovered, I'd like to get a list of its sub directories and test to see if it contains ! Issued Packages.
When I step through this code, subdirectories returns the expected array of folders and containsStorage is correctly set to true. In turn, d correctly reflects the directory name i'd like to search next, L:\\H435431 Project Name\\2-Storage. ad never gets assigned the value of Directory.GetDirectories(d) and the directory is never searched. Why is this?
string[] subirectories = Directory.GetDirectories(directory);
foreach (string d in subirectories)
{
if (Regex.IsMatch(d, #"2-Storage", RegexOptions.IgnoreCase))
{
containsStorage = true;
foreach (string ad in Directory.GetDirectories(d))
{
if (Regex.IsMatch(ad, #"! Issued Packages", RegexOptions.IgnoreCase))
{
containsIssued = true;
}
}
}
}
Check to see if SubSubDirectories is empty for us if there is nothing in there then there is nothing to iterate through.
string[] subirectories = Directory.GetDirectories(directory);
foreach (string d in subirectories)
{
if (Regex.IsMatch(d, #"2-Storage", RegexOptions.IgnoreCase))
{
containsStorage = true;
string[] subSubDirectories = Directory.GetDirectories(d);
foreach (string ad in subSubDirectories)
{
if (Regex.IsMatch(ad, #"! Issued Packages", RegexOptions.IgnoreCase))
{
containsIssued = true;
}
}
}
}
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");