So I followed MS article http://msdn.microsoft.com/en-us/library/ms171645.aspx
This is Creating an Explorer Style Interface with the ListView and TreeView Controls Using the Designer.
So all is well, howerver, is you set it to the root of C to scan all the folders and files etc. I receive {"Access to the path '<path to file' is denied."}
VS 2010 points this spot that is the issue.
subSubDirs = subDir.GetDirectories();
I can put a try catch around this are, howerver, after the exception is thrown the app doesn't continue.
Is there a way I can skip directories that the app cannot access?
You might have the try catch in the wrong place. Based on the code in the walkthrough you could put the try catch like this:
Replace:
subSubDirs = subDir.GetDirectories();
with this:
try
{
subSubDirs = subDir.GetDirectories();
}
catch(UnauthorizedAccessException uae)
{
//log that subDir.GetDirectories was not possible
}
Also, the line:
if (subSubDirs.Length != 0)
should be changed to:
if (subSubDirs != null && subSubDirs.Length != 0)
You get the exception because the calling account doesn't have access rights to folders like System Volume Information. You can get around this some by using Linq and skipping folders that are marked System or Hidden.
DirectoryInfo root = new DirectoryInfo(#"C:\");
Func<FileSystemInfo, Boolean> predicate = dir =>
(dir.Attributes & FileAttributes.System) != FileAttributes.System &&
(dir.Attributes & FileAttributes.Hidden) != FileAttributes.Hidden;
IEnumerable<FileSystemInfo> directories = root.GetDirectories().Where(predicate);
foreach (DirectoryInfo directory in directories) {
try {
Trace.WriteLine(directory.Name);
DirectoryInfo[] subdirectories = directory.GetDirectories();
}
catch (System.UnauthorizedAccessException) {
Trace.WriteLine("Insufficient access rights.");
}
}
Trace.WriteLine("End of application.");
This is not solution for every scenario though, and will fail on some files and folders. There is no easy solution using the existing API; you may want to look into getting file and directory information through WMI instead.
Related
I am trying to program a Windows service that automatically deletes the file from a specific folder. But I encountered an error:
Cannot access the file. The file is currently in use by another process/program.
I tried to do the following, but still get the same error.
string[] files = Directory.GetFiles(#"C:\Users\ASIM\AppData\Local\Temp");
// string[] directories = Directory.GetDirectories(#"C:\Users\ASIM\AppData\Local\Temp", "p*", SearchOption.TopDirectoryOnly);
if (files != null || files.Length != 0)
{
{
foreach (string f in files)
{
try
{
File.Delete(f);
}
finally { }
}
}
}
so how to skip deleting a file if it is in use?
There is no point checking if the file is deletable before deleting it because there will be a small window of opportunity between your check and the delete, where another process will open the file. The best idea is to try and delete it and handle the exception if it occurrs.
Your try/finally should be try/catch with the appropriate exception:
try
{
File.Delete(f);
}
catch(IOException ex)
{
// Probably some logging here
}
So guys, I have a function in my application which to search for certain file in certain directory using GetFiles method
System.IO.Directory.GetFiles(string path, string searchPattern, System.IO.SearchOption)
It works fine, until when I choose drive directory (D:\ or C:\ and such) to be searched, because it's also accessing the Recycle Bin, and then restricted
Access to the path 'D:\$RECYCLE.BIN\S-1-5-21-106145493-3722843178-2978326776-1010' is denied.
It's also need to be able to search subfolders (SearchOption.AllDirectories) too.
How to SKIP such place to be searched? Because there may be any other folder which access also denied.
I capitalize SKIP because if I use try catch and an exception caught, then the entire search will also fail.
Thanks. Please clarify anything you need.
EDITed for more clarity.
When recursively scanning a directory tree, say using a recursive method which takes the directory to start with as a parameter, you can get the attributes of the directory. Then check whether it's a system directory AND NOT a root directory like "C:\" - in that case you want to skip that directory, as it may be, for instance, the recycle bin.
Here's some code that does this, and also catches some common exceptions which occurred when I fiddled with directory scanning.
void scan_dir(string path)
{
// Exclude some directories according to their attributes
string[] files = null;
string skipReason = null;
var dirInfo = new DirectoryInfo( path );
var isroot = dirInfo.Root.FullName.Equals( dirInfo.FullName );
if ( // as root dirs (e.g. "C:\") apparently have the system + hidden flags set, we must check whether it's a root dir, if it is, we do NOT skip it even though those attributes are present
(dirInfo.Attributes.HasFlag( FileAttributes.System ) && !isroot) // We must not access such folders/files, or this crashes with UnauthorizedAccessException on folders like $RECYCLE.BIN
)
{ skipReason = "system file/folder, no access";
}
if ( null == skipReason )
{ try
{ files = Directory.GetFiles( path );
}
catch (UnauthorizedAccessException ex)
{ skipReason = ex.Message;
}
catch (PathTooLongException ex)
{ skipReason = ex.Message;
}
}
if (null != skipReason)
{ // perhaps do some error logging, stating skipReason
return; // we skip this directory
}
foreach (var f in files)
{ var fileAttribs = new FileInfo( f ).Attributes;
// do stuff with file if the attributes are to your liking
}
try
{ var dirs = Directory.GetDirectories( path );
foreach (var d in dirs)
{ scan_dir( d ); // recursive call
}
}
catch (PathTooLongException ex)
{ Trace.WriteLine(ex.Message);
}
}
I wrote a program (on Windows 7) that call the method DirectoryInfo.GetFiles(), and in the folder "documents and settings", I have the exception of UnauthorizedAccess.
I tried lots of solutions, like:
create a manifest with
`<requestedExecutionLevel level="highestAvailable" uiAccess="false" />`
and also with this
DirectorySecurity dSecurity = Directory.GetAccessControl(dir.FullName);
dSecurity.AddAccessRule(new FileSystemAccessRule("Luca", FileSystemRights.FullControl, AccessControlType.Allow));
Directory.SetAccessControl(dir.FullName, dSecurity);
What could be the issue?
First off, you should be using DirectoryInfo.EnumerateFiles(...) instead of GetFiles(...). EnumerateFiles(...) keeps you from having to get the entire list until you actually need to.
I ran into this issue a while back and found that I ended up needing to implement a replacement IEnumerable in order to be able to complete an enumeration over folders that I may only have selected access to.
You can see the result of my research in the following thread. DirectoryInfo.EnumerateFiles(...) causes UnauthorizedAccessException (and other exceptions)
Just a Quick Copy Paste because I just had the same Problem.
Adjust the Code to your needs (because I calculate the the size, counting all files and "save" all the Files I want to copy in a List).
After you got all files in your List you can start copy them or what ever you wanna do with the Files:
private double CalculateSize(string sourcePath, Progress state, List<FileInfo> filesToCopy)
{
int _fileCount = 0;
DirectoryInfo sourceDirectory = new DirectoryInfo(sourcePath);
FileInfo[] files = null;
try
{
files = sourceDirectory.GetFiles();
}
catch(UnauthorizedAccessException ex)
{
// DO SOME LOGGING-MAGIC IN HERE...
}
if (files != null)
{
foreach (FileInfo file in files)
{
fullSizeToCopy += file.Length;
filesToCopy.Add(file);
_fileCount++;
}
}
DirectoryInfo[] directories = null;
try
{
directories = sourceDirectory.GetDirectories();
}
catch(UnauthorizedAccessException ex)
{
// Do more logging Magic in here...
}
if (directories != null)
foreach (DirectoryInfo direcotry in directories)
{
CalculateSize(direcotry.FullName, state, filesToCopy);
}
state.FileCount = _fileCount;
return fullSizeToCopy;
}
Your best bet might be to put a try/catch block around the call and ignore any directories you don't have access to. Maybe not the best solution, but it would at least make your method get all the directories you do have access to. Something like this:
try
{
directory.GetFiles();
}
catch (UnauthorizedAccessException)
{
string logMsg = string.Format("Unable to access directory {0}", directory.FullName);
//Handle any desired logging here
}
Just like blow, use EnumerateDirectories rather than DirectoryInfo.getfiles
private void ScanEmptyDirs(string dir, ref int cnt, CancellationToken token)
{
if (String.IsNullOrEmpty(dir))
{
throw new ArgumentException("Starting directory is a null reference or an empty string: dir");
}
try
{
foreach (var d in Directory.EnumerateDirectories(dir))
{
if (token.IsCancellationRequested)
{
token.ThrowIfCancellationRequested();
}
ScanEmptyDirs(d, ref cnt, token);
}
EmptyJudge(dir, ref cnt);
}
catch (UnauthorizedAccessException) { }
}
In my network, there are some files whose access is simply blocked.
A user cannot open nor read the file.
When I try to open the file, the only message that I get is "Access Denied".
bool isReadOnly = ((File.GetAttributes(Path) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly);
I tried other options available under FileAttributes class. Nothing is matched for "Access Denied".
In short, how do I know whether a file is access-denied to me or not in c#. I am using WPF and visual studio .net 2010
Whenever I try to access it through code, I simply get an exception. When I try to open it manually I get something like "Access Denied."
try
{
IEs = from file in Directory.EnumerateFiles(sDirectoryToBeSearched, sValidExtensions, SearchOption.AllDirectories)
from str in File.ReadLines(file)
where (str.IndexOf(sSearchItem, StringComparison.OrdinalIgnoreCase) >= 0)
select file;
}
catch
{
MessageBox ("Exception arised");
}
Even If used try catch, exception is not handled because of LINQ query. Any solutions ?>
Instead of using LINQ try using recursion, that way if a file or folder access is denied the rest of procedure will continue. Example bellow.
private void SearchDirectory(string folder)
{
foreach (string file in Directory.GetFiles(folder))
{
try
{
// do work;
}
catch
{
// access to the file has been denied
}
}
foreach (string subDir in Directory.GetDirectories(folder))
{
try
{
SearchDirectory(subDir);
}
catch
{
// access to the folder has been denied
}
}
}
You don't have to check the FileAttributes, you need to check the security lists.
You can look at the example here to see how to work with the FileSecurity class.
This question already has answers here:
Ignore folders/files when Directory.GetFiles() is denied access
(8 answers)
UnauthorizedAccessException cannot resolve Directory.GetFiles failure [duplicate]
(6 answers)
Closed 2 years ago.
I'm running the code below and getting exception below. Am I forced to put this function in try catch or is there other way to get all directories recursively?
I could write my own recursive function to get files and directory. But I wonder if there is a better way.
// get all files in folder and sub-folders
var d = Directory.GetFiles(#"C:\", "*", SearchOption.AllDirectories);
// get all sub-directories
var dirs = Directory.GetDirectories(#"C:\", "*", SearchOption.AllDirectories);
"Access to the path 'C:\Documents and Settings\' is denied."
If you want to continue with the next folder after a fail, then yea; you'll have to do it yourself. I would recommend a Stack<T> (depth first) or Queue<T> (bredth first) rather than recursion, and an iterator block (yield return); then you avoid both stack-overflow and memory usage issues.
Example:
public static IEnumerable<string> GetFiles(string root, string searchPattern)
{
Stack<string> pending = new Stack<string>();
pending.Push(root);
while (pending.Count != 0)
{
var path = pending.Pop();
string[] next = null;
try
{
next = Directory.GetFiles(path, searchPattern);
}
catch { }
if(next != null && next.Length != 0)
foreach (var file in next) yield return file;
try
{
next = Directory.GetDirectories(path);
foreach (var subdir in next) pending.Push(subdir);
}
catch { }
}
}
You can set the program so you can only run as administrator.
In Visual Studio:
Right click on the Project -> Properties -> Security -> Enable ClickOnce Security Settings
After you clicked it, a file will be created under the Project's properties folder called app.manifest once this is created, you can uncheck the Enable ClickOnce Security Settings option
Open that file and change this line :
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
to:
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
This will make the program require administrator privileges, and it will guarantee you have access to that folder.
It has already been pointed out that you need to do it yourself so I thought I'd share my solution which avoids collections along the way. It should be noted that this will ignore all errors not just AccessDenied. To change that you can just make the catch blocks more specific.
IEnumerable<string> GetFiles(string folder, string filter, bool recursive)
{
string [] found = null;
try
{
found = Directory.GetFiles(folder, filter);
}
catch { }
if (found!=null)
foreach (var x in found)
yield return x;
if (recursive)
{
found = null;
try
{
found = Directory.GetDirectories(folder);
}
catch { }
if (found != null)
foreach (var x in found)
foreach (var y in GetFiles(x, filter, recursive))
yield return y;
}
}
Well, you either avoid the directories for which you don't have permissions, or you don't but then respond gracefully when access is denied.
If you choose the first option, you will need to make sure that you know what directories they are, and also that the permissions for the thread's identity do not change. This is tricky and prone to error; I wouldn't recommend it for a production-quality system.
The second option looks more appropriate. Use a try/catch block and skip any "forbidden" directories.
You can achieve this by using EnumerationOptions for the third argument. This class provides a property called IgnoreInaccessible which toggles whether an exception will be thrown if an inaccessbile file/folder is encountered.
Other properties related to searching are available too, see: EnumerationOptions Class (System.IO)
Example:
var options = new EnumerationOptions()
{
IgnoreInaccessible = true
};
var files = Directory.GetFiles("mypath", "*.*", options);
foreach (var file in files)
{
// File related activities
}
Note: IgnoreAccessible is set to true by default, but I've included it in the example above for visibility purposes.
I know this question is somewhat old, but I had this same problem today and I found the following article that explains a 'folder recursion' solution in detail.
The article acknowledges the flaws of the GetDirectories() method... :
Unfortunately, this [using the GetDirectories() method] has problems. Key amongst these is that some of
the folders that you attempt to read could be configured so that the
current user may not access them. Rather than ignoring folders to
which you have restricted access, the method throws an
UnauthorizedAccessException. However, we can circumvent this problem
by creating our own recursive folder search code.
... and then introduces the solution in detail:
http://www.blackwasp.co.uk/FolderRecursion.aspx
This recursive method will return list of all files that are accessible in the folder.
static List<string> getFilesInDir(string dirPath)
{
List<string> retVal = new List<string>();
try
{
retVal = IO.Directory.GetFiles(dirPath, "*.*", IO.SearchOption.TopDirectoryOnly).ToList();
foreach (IO.DirectoryInfo d in new IO.DirectoryInfo(dirPath).GetDirectories("*", IO.SearchOption.TopDirectoryOnly))
{
retVal.AddRange(getFilesInDir(d.FullName));
}
}
catch (Exception ex)
{
//Console.WriteLine(dirPath);
}
return retVal;
}