Removing a directory with files inside AppData - c#

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");

Related

Can Directory.Move fail because I am browsing the folder?

I have two folder in a remote FileShare and I am trying to move the first one inside the second. To do this, I wrote a CLR that pretty much does the following:
if (Directory.Exists(destinationFolder))
{
Directory.Delete(destinationFolder, true);
}
if (Directory.Exists(sourceFolder))
{
Directory.Move(sourceFolder, destinationFolder);
}
This works as expected but there are some cases that am getting the following error:
System.IO.IOException: Cannot create a file when that file already exists.
System.IO.IOException: at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) at System.IO.Directory.InternalMove(String sourceDirName, String destDirName, Boolean checkHost)
I was not able to narrow it down. It seems random to me since I can not reproduced it. I run this code block, over 50 times and I could not get the same error (or any error to tell the truth) as before.
- Do you see anything wrong with code?
- Do you have any "guesses" on what may caused this error?
The only thing I can think, is even though the Directory.Delete(destinationFolder, true); return the system does not delete the directory immediately and thus when Directory.Move(sourceFolder, destinationFolder); runs, the destinationFolder still exists.
(29/12/2016) This is not a duplicate of Cannot create a file when that file already exists when using Directory.Move. There, the user has a 'mistake' in her code and creates (Directory.CreateDirectory(destinationdirectory);) the destination folder. I am not creating the destination folder, nevertheless, I am deleting it if exists. I looked the comments and the answers but none of them gave a solution to my issue.
(30/12/2016) I have tried all the suggestions from the comments and answer but still nothing strange happens. No errors and no unexpected behaviors.
The only thing I can think [of] is even though the Directory.Delete(destinationFolder, true); return the system does not delete the directory immediately and thus when Directory.Move(sourceFolder, destinationFolder); runs, the destinationFolder still exists.
I would highly doubt that this is the cause of any issue. I suppose it is not impossible, especially since this is a folder on another system (remote file share) and not local, but I would still expect any write-behind caching being done on the remote system to be completely transparent to any file system requests, not just some of them.
I think it is more likely, given the code shown in the question, that somehow you initiated two threads at nearly the exact same time and hit a race condition wherein both threads were attempting to process the move operation at the same time. You can both detect such a condition and avoid any errors by making the following changes to your code:
string _LogFile = String.Concat(#"C:\TEMP\SQLCLR_", Guid.NewGuid(), ".log");
File.AppendAllText(_LogFile, #"Starting operation for: " + sourceFolder +
#" --> " + destinationFolder);
if (Directory.Exists(destinationFolder))
{
File.AppendAllText(_LogFile, #"Deleting: " + destinationFolder);
Directory.Delete(destinationFolder, true);
}
if (Directory.Exists(sourceFolder))
{
if (!Directory.Exists(destinationFolder))
{
File.AppendAllText(_LogFile, #"Moving: " + sourceFolder);
Directory.Move(sourceFolder, destinationFolder);
}
else
{
File.AppendAllText(_LogFile, #"Oops. " + destinationFolder +
#" already exists. How odd indeed!");
}
}
This will log the operation to a text file. It will indicate exactly which steps are being taken. It will also check for the existence of the destination before calling "move", something which is not currently being checked.
If there are two competing threads, you will get 2 log files since they are named using a GUID.
If, somehow, it actually is a delayed delete issue on the remote OS, that would be indicated by a single log file containing a line for the "Deleting.." and then one for the "Moving...". OR, if the "exists" check sees the not-yet-deleted destination, then you will see a line for "Oops".
According to MSDN you´ll get that exception in the following cases:
An attempt was made to move a directory to a different volume.
destDirName already exists.
The sourceDirName and destDirName parameters refer to the same file or directory.
The directory or a file within it is being used by another process.
You´ll have to check with some of above cases, there will be the solution for sure.
https://msdn.microsoft.com/en-us/library/system.io.directory.move(v=vs.110).aspx

Directory.Exists(#"\\SERVERIP\aFolder\bFolder"); always returns false

The following path always returns false:
Directory.Exists(#"\\SERVERIP\aFolder\bFolder");
// where SERVERIP is the server-IP which is being accessed using Impersonation
After debugging the code, it places double-slashes in the Debugger.
I have accessed the above file path without the # and double-quotes in WindowsExplorer.
What am I doing wrong?
[ The code will run on a network ]
The problem might be in the paths-[Source/Destinations] (both or one of it[source/destination] might be causing the problem) due to the default-paths used by Visual-Studio. So let me explain how to check wether the paths are correct/incorrect step by step.
Configuring ** SOURCE-PATH **:
Some times this path DRIVE:\ProgramFiles\IISExpress (or some other path depending on the installation location of IIS) gets concatenated with the SOURCE-PATH you give in the input To solve this problem, follow/verify these steps:
Ensure that the SOURCE-PATH or File you are using is in the Project-Folder
To Access the SOURCE-PATH or File. Always use this path/way:
// 1. SOURCE-PATH + fileName with Extension<br>
Server.MapPath("~\FolderInsideProjectFolder\", "fileName.extension");
Configuring ** DESTINATION-PATH (to a Mapped-NETWORK) **:
This path creates a problem if the path you entered has some words mispelled OR if you don't have access to the specified Server-IP[DestinationServerIP]. To solve this problem, follow/verify these steps:
Before Accessing the DESTINATION-PATH or File , ensure that the IP-Address you are referring to is Accessible to the Account under which your Application-code is running.To learn how to run Applications under an Account. See Impersonization
To Access the DESTINATION-PATH or File. Always use this path/way:
// 2. DESTINATION-PATH + fileName with Extension
#"\\SERVERIP\aFolder\bFolder" + "fileName.extension";
NOTE:
Remember that the SOURCE-PATH can be checked if it (exists/does not exist) by addressing its Fully-Qualified-Address and in that case, it will return true if it exists (The full-path that windows-explorer shows you in the Address Bar (Windows-Explorer) like DRIVE:/....../
EXTRA-INFORMATION: (as it was the basic INTENSION)
One line instruction to Copy the file from local-system → networked-mapped drive/path is:
System.IO.File.Copy(
Server.MapPath("~\FolderInsideProjectFolder\", "fileName.extension"),
#"\\SERVERIP\aFolder\bFolder" + "fileName.extension"
[, true ] // Optional if you want the file to be over-written or not
);
Please inform, if any thing still is not cleared (but after some nice searching ☋ ☛ )
Many a times I have seen file (or directory) access problems when the user (a human, system user such as IIS_IUSR or an application) lacks required privileges.
According to this question where the asker is facing similar problem, I believe that this may help you.
Let us know, if it helps.

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.

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