Why ArgumentException from Directory.Exist can not be catched? - c#

Why I can't catch the Argument excpetion here:
string path = "\"";
bool dirOk = true;
try
{
dirOk = Directory.Exists(path);
}
catch (ArgumentException)
{
dirOk = false;//Never gets in here
}
Edited: Sorry, bad sample path, changed now!
Config VS debugger to halt on all exceptions.VS will break saying: "ArgumentException Occurred" "Illegal characters in path.", but the try catch do nothing.
Edit 2: I think I got it, sorry. VS breaks but the exception is already catch inside Exists().

The posted code does not throw any exception...
Directory.Exists("nonsense string") just returns false.
As far as I can tell it even returns when the string contains invalid path characters or is null.
On the MSDN page there is no mention of exceptions so I assume this is very 'safe' method to call.
The page does have this to say:
The Exists method returns false if any error occurs while trying to determine if the specified file exists. This can occur in situations that raise exceptions such as passing a file name with invalid characters or too many characters, a failing or missing disk, or if the caller does not have permission to read the file.

Simply because Directory.Exists does not throw exception when the path is not valid, it only returns true or false depending on the existance of the directory.
Look in the documentation on MSDN

Directory.Exists(string path) is not throwing exceptions at all. This seems to be a classic RTFM case ;)
As stated here the method just returns false on any parameter that is not specifying an absolute or relative path.

Related

Removing a directory with files inside AppData

Well, what I want to do is to remove my folder that is located inside Roaming. I want this to work for every user, so the username of every PC is different. I already know that to get path of AppData I need following:
var path = Environment.SpecialFolder.ApplicationData;
But what to do to remove the folder with a specific name (Let's call it ExampleDir)? I tried this:
Path.Combine(path + "Kappa");
Directory.Delete(true.ToString());
But this does not work. I am beginner at C#, still, I want to practice. Will be grateful for help =)
First of all, Path.Combine() is used to replace string concatenation so don't concatenate strings in it. Pass every name you want to concatenate as a parameter and the function will do the rest.
Secondly, to remove a folder containing files you have to use the Directory.Delete(string, bool) overload. The bool value (called recursive) indicates wether you want to remove files and subfolders in the specified directory (see the MSDN Documentation for Directory.Delete()).
And finally, Environment.SpecialFolder.ApplicationData is just an enumration (meaning it's just a number). You have to pass it as a parameter to the Environment.GetFolderPath() method to get the actual path of the AppData folder.
Example:
string AppDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string FolderToDelete = Path.Combine(AppDataFolder, "Kappa");
try
{
Directory.Delete(FolderToDelete, true); //Setting "recursive" to true will remove every subfile/-folder.
}
catch (Exception ex)
{
//An error occurred, use this block to log it/show it to the user/whatever.
//ex.Message - The error message.
//ex.StackTrace - Where in the code the error occurred.
}
EDIT:
As #dman2306 said in his comment, some exception handling is good practice in case of that the deletion fails. I have added this to my above code.
The code in the try block will run until an exception is thrown (if any). If an exception is thrown the execution will move on to the catch block, which is where you catch the exception and perform for example error logging, stopping other procedures, etc.
EDIT 2:
You possibly have to add "Roaming" to Path.Combine(). I am unsure if it's already included or not, and I'm unable to test that now.
string FolderToDelete = Path.Combine(AppDataFolder, "Roaming", "Kappa");
Forget what I said, SpecialFolder.ApplicationData gives you the path to the Roaming folder.
First of all you are using Path.Combine() wrong. But you don't need that at all.
Second you have to use backslases to separate folders in a path when combining them with +.
And third: The method Directory.Delete() wants the path of the folder you want to delete as an argument.
Try this:
Directory.Delete(Environment.SpecialFolder.ApplicationData + "\\Kappa");

Could trying to copy a file owned by another process cause a DirectoryNotFoundException?

The log I'm trying to work with belongs to another program that runs concurrently with my own. I get a DirectoryNotFoundException stating "Could not find a part of the path " when I try to make the copy. The assert does pass. The exception is thrown at File.Copy(...) itself. With the if(File.Exists(...)) in place, the program is clearly able to see the file before it attempts to copy it.
Edit: Could permissions be a possible cause? The directory is located in the root of the C drive.
Edit: By adding the two asserts suggested by Jim Mischel and stepping through in the cold light of a new day, newControlProgramLog path was revealed as the culprit. GetSaveFilePath() was returning a default path for the particular run state I was testing. I declared the default but never checked to see that it existed on program start up. The directory is now created if it does not exist, and the function now works as intended.
Shout out to Christian Hagelid for calling that it wasn't an issue with controlProgramLogPath from the start.
private void CopyLogsToDataDirectoy()
{
Debug.Assert(Directory.Exists(_controlProgramDirectory));
string controlProgramLogPath = Path.Combine(_controlProgramDirectory, _controlProgramLogFileName);
if (File.Exists(controlProgramLogPath))
{
string dataFilePath = GetSaveFilePath();
string newControlProgramLogName = Path.GetFileNameWithoutExtension(dataFilePath);
newControlProgramLogName = newControlProgramLogName + ".control.log";
string newControlProgramLogPath = Path.GetDirectoryName(dataFilePath);
newControlProgramLogPath = Path.Combine(newControlProgramLogPath, newControlProgramLogName);
File.Copy(controlProgramLogPath, newControlProgramLogPath);
}
}
DirectoryNotFoundException occurs when part of the path you specified does not exist. It does not occur because a file is locked. If you get DirectoryNotFoundException, then it's almost certainly because the string you supplied does not reference a valid directory path. Documentation also says that you can get this exception if your code doesn't have the PathDiscovery permission. I suspect that's pretty unlikely in your case.
You should check the paths in controlProgramLogPath and newControlProgramLogPath immediately before calling File.Copy.
Debug.Assert(Directory.Exists(Path.GetDirectoryName(controlProgramLogPath));
Debug.Assert(Directory.Exists(Path.GetDirectoryName(newControlProgramLogPath));
I suspect that will reveal the problem.

Ignore exception and add file to a list?

I asked a question yesterday, and recieved great help (especially from #AviTurner).
I have further developed the program I was working on yesterday, and I have encountered a new problem.
The code of my program can be found here.
Basicly what it does, is:
The user can select a path of a directory, and the program scans all files for read-only attribute.
It sets the read-only attribute on those files that does not currently have it.
Now the problem occurs, when it encounters a file that is currently in use (such as system files).
I have been told there is no way around this, but I thought:
Is there a way to ignore the error (by this I mean continue the program, just skip this file); and add the name of the file to a list for later tracking purposes?
I hope I made my problem clear.
Thanks.
try surrounding your code in try/catch:
try
{
System.IO.FileAttributes attr = System.IO.File.GetAttributes(file);
}
catch(Exception ex)
{
files.add(file)
}
basically if you get an exception in the try block, the program executes the catch block
I suggest...
try
{
System.IO.File.SetAttributes(file, attr);
}
catch // You can specify a specific error with catch(UnauthorizedAccessException ex) for instance.
{
filesInError.Add(file); // A list<string>() to keep track of errors.
}
Here the details, and exceptions raised, by the SetAttributes().
SetAttributes on MSDN
And some explanations about try catch if you're not familiar with.
try ... catch on MSDN

Why does System.IO.File.Exists(string path) return false?

System.IO.File.Exists(string path)
returns always false, even when the file exists on the specified path. What could be the possible solution?
It could well be a permission problem. From the documentation:
The Exists method returns false if any error occurs while trying to determine if the specified file exists. This can occur in situations that raise exceptions such as passing a file name with invalid characters or too many characters, a failing or missing disk, or if the caller does not have permission to read the file.
One way of seeing what's happening is to just try to read the file (e.g. with File.OpenRead). I'd be surprised if that succeeds - but if it fails, the exception should give you more information.
Hiding file endings in windows can sometimes cause confusion: you KNOW your file is named file.txt when it is actually named file.txt.txt because the last 4 characters have been hidden by the OS.
One possibility not mentioned in any of the answers here is 'File System Redirection' on Windows 8.1 onward.
For example, if your program is a 32-bit application and you're running on 64-bit Windows then an attempt to access %windir%\System32 would be redirected to %windir%\SysWOW64. And if the file you're trying to access doesn't exist in %windir%\SysWOW64 then System.IO.File.Exists(string path) would return False.
Link to a nice article explaining this behavior
I was puzzling over this as well, then realized I was using File.Exists when I should have been using Directory.Exists.
in my case, a different "dash" in file name causes the issue.
var f1 = "4-37R.pdf";
var f2 = "4‐37R.pdf";
var r = f1==f2?"same":"diff";
Console.Write(r); //diff
turns out
var c1 = '-';
var c2 = '‐';
Console.WriteLine((int)c1); //45
Console.WriteLine((int)c2); //8208
use the same '-' fixes the issue.
How I got around this was using Server.MapPath(fileName) as it kept trying to find the file somewhere else.
System.IO.File.Exists(Server.MapPath(string path))
This had me stumped for a while while I was debugging a service locally, I was running File.Exists("U:\dir1") against a server location mapped on my workstation as (U:). I replaced the U:\dir1 to "\\serverPath\dir1" and File.Exists then returned true.
I was experiencing this myself too. In my case, I was deleting the file and re-creating it. In the process that was deleting the file, I forgot to add in WaitForExit() before using File.Exists later on
I just learned today that System.IO.File.Exists will return false if the file exists but is empty
System.IO.File.Exists(string path) returned false for me while trying to read C:\OpenSSL\bin\file.txt.
Running the application in Administrator mode did not help.
(I was logged on the administrator account, Windows 10)
Once I moved the file to C:\Users\MyUser\Desktop\file.txt, File.Exists() returned true.
Here's one more, which took me far too long to twig to.
The file name was in a constructed variable that was use to write the file, then the same variable used to check that it had been successfully written, so it could not have been different versions of '-'. I am running mono on Linux and debugging as a different user than the program is normally run by/as. Many of these types of errors are related to permissions and I spent a while banging my head on that. When File.OpenRead also threw "file not found" I finally noticed my file name had a space character at the end. I only saw this when I copied the exception message, which showed quote marks around the file name string, revealing the included space.
Apparently you can write a file name with a trailing space, but File.Exists trims that off and doesn't recognize it. When I eliminated the trailing space File.Exists worked as expected.
There can be requirement to use the DirectoryProvider Refresh() process to get the correct result from the Exists function.
e.g. code as per:
private DirectoryInfo CreateDirectory(string folderPath, int code, string message)
{
DirectoryInfo di;
try
{
di = DirectoryProvider.CreateDirectory(folderPath);
}
catch
{
throw new WebServiceException(code, HttpStatusCode.BadRequest, message);
}
di.Refresh();
if (!DirectoryProvider.Exists(di))
{
throw new WebServiceException(code, HttpStatusCode.BadRequest, message);
}
return di;
}
I was using System.IO.Path.Combine and assuming it would remove any trailing white space. For the life of me I could figure out why System.IO.File.Exists(path) was returning false.
I used the below snippet to test why it was failing
Turns out that a trailing white space was introduced causing an
"The filename, directory name, or volume label syntax is incorrect inside batch"
Hopefully someone will avoid the same stupid mistake as me
bool FileExists(string path){
try
{
using var stream = File.Open(path, FileMode.Open);
return true;
}
catch (FileNotFoundException)
{
return false;
}
catch (DirectoryNotFoundException)
{
return false;
}
catch (UnauthorizedAccessException ex)
{
Console.WriteLine(ex.message);
throw;
}
catch (Exception ex)
{
Console.WriteLine(ex.message);
throw;
}
}

File Not Found, but the file is there!

public static List<Product> Load(string filename)
{
if (!File.Exists(filename))
{
throw new FileNotFoundException("Data could not be found ", filename );
}
}
Visual Studio 2010 gives the following exception, "FileNotFoundException"
emmm.. ok. this problem seem to have been solved.
.
But however, I still can not find the file!! But the file is there, in the same directory, Ive already verified and double-verified the name is correct! I have no idea what is going on.
The file is called "Products.xml".
You are the one who is throwing the exception. Do you mean to put up an error message?
File.Exists may return false if the user that the code runs under does not have access to the file, as well as if the does not exist.
http://msdn.microsoft.com/en-us/library/system.io.file.exists.aspx
The file is called "Products.xml".
You expose yourself to random failure with a filename like that. You should use the full path name of the file, like c:\mumble\foo\products.xml. If you don't then you completely rely on your program's working directory being set correctly. The value of Environment.CurrentDirectory.
Even if it is set correctly by whatever program is starting yours (like a shortcut on the desktop), you still can get into trouble when code you didn't write changes the working directory. A good example is OpenFileDialog with the RestoreDirectory property left to the default value of false.
Always use full path names in your code. Or let the user select the file.
It looks like the problem is File.Exists is returning false and you're throwing an exception which is not handled by your code. Did you intend for this exception to be handled or does this represent a fatal error to your program?
The file located at filename does not exist, and thus it throws the exception with the following line: throw new FileNotFoundException("Data could not be found ", filename );
Did you mean to just output an error?
In you code first check for empty filename as the passed parameter may be empty string, plus apply try catch block on the code as the passed filename might not satisfy the path rules for a file. in catch block through your exception too.
You either:
A) Don't want to throw the exception via this line
throw new FileNotFoundException()
and instead want to display a Dialog to the user, or use some other error handling technique in there. To output an error either use one of the following:
Console.WriteLine("File not found")
MessageBox.Show("File not found");
B) Higher up in your call stack have a try/catch and handle your error there, similarly with a dialog or another error handling approach suitable for your application.
try
{
Load(filename);
}
catch(FileNotFoundException fe)
{}

Categories