I'm a bit confused here. I wrote the following script to add files of a certain extension type to a List and it DOES work, just not for the root of C: Here's the code first...
// Create an empty list
List<string> scanFiles = new List<string>();
// Split possible extention list into array
string[] scanExtensions = #"exe,com".Split(',');
try
{
foreach (string extension in scanExtensions)
{
// Add collection for this filetype to the list of files
scanFiles.AddRange(Directory.GetFiles("C:\\", "*." + extension, SearchOption.AllDirectories));
}
}
catch (Exception ex)
{
Console.WriteLine("ERROR: " + ex.Message);
}
// Display results
foreach(string sf in scanFiles)
{
Console.WriteLine(sf);
}
So if I run the above code, I get an error - but not the error I expect. It displays the following...
ERROR: Access to the path 'C:\Documents and Settings\' is denied.
I'd understand this if I hadn't specified 'C:\' as the directory path! If I change this to any valid directory (such as C:\Program Files), the code works fine. Can anyone explain this?
Thanks,
Simon
SearchOption.AllDirectories means your code will drill down into (forbidden) territory.
Better be prepared to handle this kind of error. For a solution without catching exceptions you'll need DirectoryInfo.GetFiles() to get FileInfo objects instead of strings and verify your access rights ahead of time.
But you will still need to handle exceptions (File/Dir not found) because of concurrency so you might as well forget about the FileInfos.
Well, the cause of the error message called "Access denied" is ... that you don't have access to that folder!
Try clicking on it in Windows Explorer. You will notice that, in fact, you can't access it. What a surprise ;-) The message told you exactly that.
SearchOption.AllDirectories means that GetFiles will recursively enumerate all files. If it hits an error somewhere it will throw an exception. There is no way to change that.
You cannot make Directory.GetFiles ignore access denied errors. So you have to code your own file-system enumeration code. It will probably be a recursive function with some error-handling code in it.
You're specifying SearchOption.AllDirectories which according to the documentation means
AllDirectories Includes the current directory and all the subdirectories in a search operation. This option includes reparse points like mounted drives and symbolic links in the search.
In other words, your search is recursive and walks down into Documents and Settings where you have no read permission.
Related
I need compact all the folders of my E:\ But when i try with this code, i get this access exception.
I'm new on programming and are trying learn how a i can do this work.
I'm using the dotnetzip for compact the directories inside E:.
Some parts of the code are just copied, i know that... but i'm trying learn how to do work.
I already tried some others solution for solve the problem answered here.
Like add a manifest to the project who requeireAdministrator permissions to run and insert a Access Control Rule to modify the security of E:\ Something that i notice when do this is my user have permissions removed from the subfiles and directories of E:\ But without this access rule the same exception keep existing.
try
{
ZipFile zip = new ZipFile();
zip.AddDirectory(#"E:\");
zip.Save(#"C:\Users\vitorbento\Desktop\backup.zip");
Console.WriteLine("Compactação concluída");
Console.WriteLine("Done.");
}
catch (UnauthorizedAccessException)
{
FileAttributes attr = (new FileInfo(DirectPath)).Attributes;
Console.Write("UnAuthorizedAccessException: Unable to access file. ");
if ((attr & FileAttributes.ReadOnly) > 0)
Console.Write("The file is read-only.");
}
This is similar with this question but with one more requirement:
Since the deletion of files can fail for whatever reasons. So I want the operation to be "transacted" which mean the whole operation either success in total, or fail and do not change anything at all.
In general this will be very very hard and I can't see any possibility to recover when the physical hard drive suddenly broken. So a weakened clause would be: if it success, we finished. Otherwise if fail, restore everything to the original state when possible.
Some kind of errors I could think of would be:
Access violation. You simply don't allowed to delete some files or folders. This is the case that I wanted to handle the most.
File/folder was used by somebody else and so it is "locked". In Linux this is not a problem but in Windows it is. This is also to be handled.
If it is a network folder there could be network issues. The recover can be hard or impossible. I would not expect this kind of error to be properly handled.
Hardware failure. I don't think any recover can happen here.
Scenario
You have a software that can export its internal data. The result is in a folder and with sub-folder names timestamped.
Now if the user specified a folder that is not empty (probably a previous output folder), the software will create new sub-folders on top of it, which is a mass. So you want to ensure the folder is empty before performing the export.
You can easily detect the folder emptiness and alert the user if not. But if the user say "go ahead and do it" you should do something then. Now, what if you were deleted some of the files and failed on others?
Going ahead in this case is just creating worse mass. At the same time the user would not expect a damaged folder without getting anything working. So it is better to either give them a fully working output or does not change the previous output at all.
As per comments, I'll give you the pseudocode for the process you can follow writing the code:
Clear contents of cache folder if any files exist (they shouldn't)
Copy contents of destination folder to cache folder
Try
While files exist, iterate
Delete file
End While
Catch
While files exist in cache, iterate
If file does not exist in destination folder
Move file from cache to destination
else
Delete file from cache
end If
End While
End Try
By following the guidelines given in the comments, I came up with this solution.
The following code will attempt to move everything to a temporary folder inside the given folder. If success, it returns True. If failed, the catch block will then try to move everything back and return a False. In either case, the finally block will remove the temporary folder recursively.
public static bool EmptyFolderTransactionaly(string folder)
{
var directoryInfo = new DirectoryInfo(folder);
var tmpDir = Directory.CreateDirectory(Path.Combine(folder, Path.GetFileName(Path.GetTempFileName())));
try
{
foreach (var e in directoryInfo.EnumerateFiles())
{
e.MoveTo(Path.Combine(tmpDir.FullName, e.Name));
}
foreach (var e in directoryInfo.EnumerateDirectories().Where(e => e.Name!=tmpDir.Name))
{
e.MoveTo(Path.Combine(tmpDir.FullName, e.Name));
}
return true;
}
catch
{
foreach (var e in tmpDir.EnumerateDirectories())
{
e.MoveTo(Path.Combine(directoryInfo.FullName, e.Name));
}
foreach (var e in tmpDir.EnumerateFiles())
{
e.MoveTo(Path.Combine(directoryInfo.FullName, e.Name));
}
return false;
}
finally
{
tmpDir.Delete(true);
}
}
Let me know if you see any risks in the code.
I am programming in c# and want to copy a folder with subfolders from a flash disk to startup.
Here is my code:
private void copyBat()
{
try
{
string source_dir = "E:\\Debug\\VipBat";
string destination_dir = "C:\\Users\\pc\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup";
if (!System.IO.Directory.Exists(destination_dir))
{
System.IO.Directory.CreateDirectory(destination_dir);
}
// Create subdirectory structure in destination
foreach (string dir in Directory.GetDirectories(source_dir, "*", System.IO.SearchOption.AllDirectories))
{
Directory.CreateDirectory(destination_dir + dir.Substring(source_dir.Length));
}
foreach (string file_name in Directory.GetFiles(source_dir, "*.*", System.IO.SearchOption.AllDirectories))
{
File.Copy(file_name, destination_dir + file_name.Substring(source_dir.Length), true);
}
}
catch (Exception e)
{
MessageBox.Show(e.Message, "HATA", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
I got an error:
Could not find a part of the path E:\Debug\VipBat
The path you are trying to access is not present.
string source_dir = "E:\\Debug\\VipBat\\{0}";
I'm sure that this is not the correct path. Debug folder directly in E: drive looks wrong to me. I guess there must be the project name folder directory present.
Second thing; what is {0} in your string. I am sure that it is an argument placeholder because folder name cannot contains {0} such name. So you need to use String.Format() to replace the actual value.
string source_dir = String.Format("E:\\Debug\\VipBat\\{0}",variableName);
But first check the path existence that you are trying to access.
There's something wrong. You have written:
string source_dir = #"E:\\Debug\\VipBat\\{0}";
and the error was
Could not find a part of the path E\Debug\VCCSBat
This is not the same directory.
In your code there's a problem, you have to use:
string source_dir = #"E:\Debug\VipBat"; // remove {0} and the \\ if using #
or
string source_dir = "E:\\Debug\\VipBat"; // remove {0} and the # if using \\
Is the drive E a mapped drive? Then, it can be created by another account other than the user account. This may be the cause of the error.
I had the same error, although in my case the problem was with the formatting of the DESTINATION path. The comments above are correct with respect to debugging the path string formatting, but there seems to be a bug in the File.Copy exception reporting where it still throws back the SOURCE path instead of the DESTINATION path. So don't forget to look here as well.
-TC
Probably unrelated, but consider using Path.Combine instead of destination_dir + dir.Substring(...). From the look of it, your .Substring() will leave a backlash at the beginning, but the helper classes like Path are there for a reason.
There can be one of the two cause for this error:
Path is not correct - but it is less likely as CreateDirectory should create any path unless path itself is not valid, read invalid characters
Account through which your application is running don't have rights to create directory at path location, like if you are trying to create directory on shared drive with not enough privileges etc
File.Copy(file_name, destination_dir + file_name.Substring(source_dir.Length), true);
This line has the error because what the code expected is the directory name + file name, not the file name.
This is the correct one
File.Copy(source_dir + file_name, destination_dir + file_name.Substring(source_dir.Length), true);
We just had this error message occur because the full path was greater than 260 characters -- the Windows limit for a path and file name. The error message is misleading in this case, but shortening the path solved it for us, if that's an option.
I resolved a similar issue by simply restarting Visual Studio with admin rights.
The problem was because it couldn't open one project related to Sharepoint without elevated access.
This could also be the issue: Space in the folder name
Example:
Let this be your path:
string source_dir = #"E:\Debug\VipBat";
If you try accessing this location without trying to check if directory exists, and just in case the directory had a space at the end, like :
"VipBat ", instead of just "VipBat" the space at the end will not be visible when you see in the file explorer.
So make sure you got the correct folder name and dont add spaces to folder names. And a best practice is to check if folder exists before you keep the file there.
Any way to check if write permissions are available on a given path that could be either a local folder (c:\temp) or a UNC (\server\share)? I can't use try/catch because I might have write permissions but not delete so I wouldn't be able to delete created file...
Yes you can use the FileIOPermission class and the FileIOPermissionAccess enum.
FileIOPermissionAccess.Write:
Access to write to or delete a file or directory. Write access includes deleting and overwriting files or directories.
FileIOPermission f = new FileIOPermission(FileIOPermissionAccess.Write, myPath);
try
{
f.Demand();
//permission to write/delete/overwrite
}
catch (SecurityException s)
{
//there is no permission to write/delete/overwrite
}
You use a permissions demand, thus:
FileIOPermission f2 = new FileIOPermission(FileIOPermissionAccess.Read, "C:\\test_r");
f2.AddPathList(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, "C:\\example\\out.txt");
try
{
f2.Demand();
// do something useful with the file here
}
catch (SecurityException s)
{
Console.WriteLine(s.Message);
// deal with the lack of permissions here.
}
specifying the permissions you want and the file system object(s) desired. If you don't have the demanded permission, a Security exception is thrown. More details at
http://support.microsoft.com/kb/315529
http://msdn.microsoft.com/en-us/library/system.security.permissions.fileiopermission.aspx
For a variety of reasons — race conditions being one of them — it's more complicated than it might seem to examine NTFS file system permissions.
Apparently, we figured out a while back that this is a no-op for UNC paths. See this question, Testing a UNC Path's "Accessability", for detials.
A little google-fu suggests that this CodeProject class might be of use, though: http://www.codeproject.com/Articles/14402/Testing-File-Access-Rights-in-NET-2-0
In my app, I have built a system where users can create picture galleries. Photos held in folders in the format of category_name/gallery_name/{pictures} on disk. Each uploaded photo is stored under relevant directory structure as given above.
When trying to delete a category though, as well as deleting from the database, I want to delete relevant folders from the system too. When I first received the error message "Directory is not empty" I searched and found this solution:
public static void DeleteDirectory(string target_dir)
{
string[] files = Directory.GetFiles(target_dir);
string[] dirs = Directory.GetDirectories(target_dir);
foreach (string file in files)
{
File.SetAttributes(file, FileAttributes.Normal);
File.Delete(file);
}
foreach (string dir in dirs)
{
DeleteDirectory(dir);
}
Directory.Delete(target_dir, false);
}
With this solution, photos in the "gallery_name" folder gets deleted just fine, then the gallery_name folder itself gets deleted fine.. so we are now left with an empty category_name folder. Then the last bit of code in the above subroutine (Directory.Delete(target_dir, false);) gets called to delete the category_name folder. The error raises again..
Does anyone knows a solution to this?
Directory.Delete(target_dir, true); did not work, that is why I tried an alternative.
I have full control over the parent folder and the category_name and gallery_name folders are also created programmatically without any problem.
As I mentioned, the sub directories (gallery_name folders) and their contents (photos) are deleted with this code just fine. It is the category_name folder which causes the error, even though after this code, it is just an empty folder.
The exception message I get is:
System.IO.IOException was unhandled by user code
HResult=-2147024751
Message=The directory is not empty.
Source=mscorlib
StackTrace:
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.Directory.DeleteHelper(String fullPath, String userPath, Boolean recursive, Boolean throwOnTopLevelDirectoryNotFound)
at System.IO.Directory.Delete(String fullPath, String userPath, Boolean recursive, Boolean checkHost)
at System.IO.Directory.Delete(String path)
at MyApp.PhotoGallery.Categories.deleteCategory(Int32 cID, String categoryname) in d:\Documents\My Dropbox\web projects\MyAppFolder\App_Code\BLL\PhotoGallery.vb:line 291
at _admhades_PhotoGallery.deleteCategory(Int32 categoryID, String categoryname) in d:\Documents\My Dropbox\web projects\HavadisPre\_admhades\PhotoGallery.aspx.vb:line 71
You may just use Directory.Delete(target_dir, true); to remove directory and all files recursively. You don't have to write custom function.
This works for me, even though i have File Explorer open:
public static void DeleteFilesAndFoldersRecursively(string target_dir)
{
foreach (string file in Directory.GetFiles(target_dir))
{
File.Delete(file);
}
foreach (string subDir in Directory.GetDirectories(target_dir))
{
DeleteFilesAndFoldersRecursively(subDir);
}
Thread.Sleep(1); // This makes the difference between whether it works or not. Sleep(0) is not enough.
Directory.Delete(target_dir);
}
This issue was driving me crazy. I was seeing the EXACT behavior of the poster when using Directory.Delete(dirPath, recursive: true); to delete a directory and it's contents. And just like the poster, even though the call threw an exception stating "Directory is not empty." the call had actually deleted all the contents of the directory recursively BUT failed to delete the root directory of the path provided. Craziness.
In my case I found that the issue was brought on by whether left nav tree in window's explorer showed the directory open which I was trying to delete. If so, then some sort of queued delete or caching of the delete of the directory's contents seems to be occurring causing the issue. This behavior can seem squirrely and unpredictable because viewing the directory in windows explorer that is to be deleted does not cause this issue as long as the directory is not open in the Windows left nav tree.
A few pictures are probably necessary to make this clear. Notice in the path below that the window is showing 1346. 1346 is a child directory of directory 1001. In this case a call to delete 1346 recursively will succeed because it's not an issue that we are looking at 1346 in Window's explorer per se.
But in the picture below, notice that in the path below we are looking at directory 1018. BUT in the left nave we have directory 1349 opened up (see arrow). THIS IS WHAT CAUSES THE ISSUE, at least for me. If in this situation we call Directory.Delete(dirPath, recursive: true); for the dirPath of directory 1349 it will throw a "Directory is not empty." exception. But if we check the directory after the exception occurrs we will find that it has deleted all the contents of the directory and it is in fact now empty.
So this seems very much like an edge case scenario but it's one we developers can run into because when we are testing code we are wanting to watch to see if the folder gets deleted. And it's challenging to understand what's triggering it because it's about the left nav bar of windows explorer not the main contents area of the window.
Anyway, as much as I dislike the code below, it does solve the problem for me in all cases:
//delete the directory and it's contents if the directory exists
if (Directory.Exists(dirPath)) {
try {
Directory.Delete(dirPath, recursive: true); //throws if directory doesn't exist.
} catch {
//HACK because the recursive delete will throw with an "Directory is not empty."
//exception after it deletes all the contents of the diretory if the directory
//is open in the left nav of Windows's explorer tree. This appears to be a caching
//or queuing latency issue. Waiting 2 secs for the recursive delete of the directory's
//contents to take effect solved the issue for me. Hate it I do, but it was the only
//way I found to work around the issue.
Thread.Sleep(2000); //wait 2 seconds
Directory.Delete(dirPath, recursive: true);
}
}
I hope this helps others. It took quite a bit of time to track down and explain because it's really odd behavior.
This isn't as complete as I'd like, but these are things that have helped me in the past when I faced similar issues.
The file is in use by something else. This means you've created a folder/file and have not yet released it. Use .Close() (where applicable).
A lock related issue.
You have used the Directory.Delete(rootFolder, true) (where true means delete recursively) when there are no folders within the root folder specified.
It is open by another program. Now, I have NO idea where to begin on this other than installing Process Monitor which can help but that only really works in some situations.
Things like Anti Virus, or even (on Windows) things like Defender have caused this issue in the past.
When you call Directory.Delete and a file is open in such way,
Directory.Delete succeeds in deleting all files but when
Directory.Delete calls RemoveDirectory a "directory is not empty"
exception is thrown because there is a file marked for deletion but
not actually deleted.
The obvious things includes make sure you have permission to delete the folder (not just you, but the account the program runs under).
The file you are trying to delete is readonly. Change the file attributes of all files in the folder first from read-only.
The path is shared by other Windows components so becareful where you are creating/deleting folders.
Source
Source
In my case, I have created my directory with my program running as administrator. When I tried to delete the same directory without administrator rights, I got the "Directory is not empty" error.
Solution: Either run the application as administrator or delete it manually.