browse by category or date

After a very long pause, I decided to resume on reading this book:

I was reading on System.Collections.Concurrent when I stopped last time. To help my brain familiar with this namespace, I decided to write a simple project. One part of the project is to enumerate files in a directory. For that, I use DirectoryInfo.GetFiles(). This is when I encountered this exception:

Unhandled exception. System.AggregateException: One or more errors occurred. (Access to the path 'D:\Config.Msi' is denied.)
 ---> System.UnauthorizedAccessException: Access to the path 'D:\Config.Msi' is denied.
   at System.IO.Enumeration.FileSystemEnumerator`1.CreateDirectoryHandle(String path, Boolean ignoreNotFound)
   at System.IO.Enumeration.FileSystemEnumerator`1.Init()
   at System.IO.Enumeration.FileSystemEnumerable`1..ctor(String directory, FindTransform transform, EnumerationOptions options, Boolean isNormalized)
   at System.IO.Enumeration.FileSystemEnumerableFactory.DirectoryInfos(String directory, String expression, EnumerationOptions options, Boolean isNormalized)
   at System.IO.DirectoryInfo.InternalEnumerateInfos(String path, String searchPattern, SearchTarget searchTarget, EnumerationOptions options)
   at System.IO.DirectoryInfo.GetDirectories(String searchPattern, EnumerationOptions enumerationOptions)

I tried to use Directory.GetFiles(), but the same exception stopped me. The first result of googling this exception is this stackoverflow question. Somehow the accepted answer is actually wrong. But if we scrolled down further, someone did gave the correct answer.

var options = new EnumerationOptions()
{
    IgnoreInaccessible = true
};

var files = Directory.GetFiles("c:\\", "*.*", options);

foreach (var file in files)
{
    // File related activities
}

Unfortunately, as the documentation states, this solution is not available in all .NET version

ProductVersions
.NET5.0, 6.0 Preview 3
.NET Core2.1, 2.2, 3.0, 3.1
.NET Standard2.1

If you’re still using the older version of .NET, you’re in luck. Because a Win32 API Ninja did provided a solution on MSDN Forums:

using System;
using System.Collections.Generic;
using System.IO;

namespace EnumerateDirectory
{
    public class EnumerateDirectory : IEnumerable<String>, IEnumerator<string>
    {
        [Serializable,
        System.Runtime.InteropServices.StructLayout
        (System.Runtime.InteropServices.LayoutKind.Sequential,
        CharSet = System.Runtime.InteropServices.CharSet.Auto
        ),
        System.Runtime.InteropServices.BestFitMapping(false)]
        private struct WIN32_FIND_DATA
        {
            public int dwFileAttributes;
            public int ftCreationTime_dwLowDateTime;
            public int ftCreationTime_dwHighDateTime;
            public int ftLastAccessTime_dwLowDateTime;
            public int ftLastAccessTime_dwHighDateTime;
            public int ftLastWriteTime_dwLowDateTime;
            public int ftLastWriteTime_dwHighDateTime;
            public int nFileSizeHigh;
            public int nFileSizeLow;
            public int dwReserved0;
            public int dwReserved1;

            [System.Runtime.InteropServices.MarshalAs
            (System.Runtime.InteropServices.UnmanagedType.ByValTStr,
            SizeConst = 260)]
            public string cFileName;

            [System.Runtime.InteropServices.MarshalAs
            (System.Runtime.InteropServices.UnmanagedType.ByValTStr,
            SizeConst = 14)]
            public string cAlternateFileName;
        }

        [System.Runtime.InteropServices.DllImport(
            "kernel32.dll",
            CharSet = System.Runtime.InteropServices.CharSet.Auto,
            SetLastError = true)]
        private static extern IntPtr FindFirstFile(string pFileName, ref WIN32_FIND_DATA pFindFileData);

        [System.Runtime.InteropServices.DllImport(
            "kernel32.dll",
            CharSet = System.Runtime.InteropServices.CharSet.Auto,
            SetLastError = true
            )]
        private static extern bool FindNextFile(IntPtr hndFindFile, ref WIN32_FIND_DATA lpFindFileData);

        [System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool FindClose(IntPtr hndFindFile);

        private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);

        public class FILETIME
        {
            public long dwLowDateTime;
            public long dwHighDateTime;
        }

        public class SYSTEMTIME
        {
            public int wYear;
            public int wMonth;
            public int wDayOfWeek;
            public int wDay;
            public int wHour;
            public int wMinute;
            public int wSecond;
            public int wMilliseconds;
        }

        Stack<SearchHandle> handles = new Stack<SearchHandle>();
        String dir;
        bool sub;

        public EnumerateDirectory(String directory)
        {
            init(directory, false);
        }

        public EnumerateDirectory(String directory, bool SearchSubdirectories)
        {
            init(directory, SearchSubdirectories);
        }

        protected void init(String directory, bool searchsubdirectories)
        {
            if (!Directory.Exists(directory))
                throw new ArgumentException("Directory does not exist.");
            dir = directory;
            sub = searchsubdirectories;

        }

        public IEnumerator<string> GetEnumerator()
        {
            Reset();
            return this;
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            Reset();
            return this;
        }

        public string Current
        {
            get;
            protected set;
        }

        public void Dispose()
        {
            foreach (var handle in handles)
                FindClose(handle.handle);
            handles.Clear();
        }

        protected void Pop()
        {
            var handle = handles.Pop();
            FindClose(handle.handle);
        }

        object System.Collections.IEnumerator.Current
        {
            get { return Current; }
        }

        public bool MoveNext()
        {
            Current = GetNextFile();
            return Current != null;
        }

        protected String GetNextFile()
        {
            WIN32_FIND_DATA data = new WIN32_FIND_DATA();
            String res = null;
            if (handles.Count == 0)
                return null;
            FindNextFile(handles.Peek().handle, ref data);
            if (data.dwFileAttributes == 16)
            {
                if (sub)
                {
                    var newHandle = getNewHandle(Path.Combine(handles.Peek().dir, data.cFileName));
                    handles.Push(newHandle);
                    return GetNextFile();
                }
                else
                {
                    return GetNextFile();
                }
            }
            else
            {
                if (String.IsNullOrEmpty(data.cFileName))
                {
                    if (handles.Count > 0)
                    {
                        Pop();
                        res = GetNextFile();
                    }
                    else
                        res = null;
                }
                else
                    res = Path.Combine(handles.Peek().dir, data.cFileName);
            }
            return res;
        }

        public void Reset()
        {
            Dispose();
            handles.Push(getNewHandle(dir));
        }

        private SearchHandle getNewHandle(String directory)
        {
            var data = new WIN32_FIND_DATA();
            var handle = FindFirstFile(Path.Combine(directory, "*"), ref data);
            FindNextFile(handle, ref data);
            return new SearchHandle(handle, directory);
        }

    }

    class SearchHandle
    {
        public IntPtr handle;
        public String dir;

        public SearchHandle(IntPtr handle, String dir)
        {
            this.handle = handle;
            this.dir = dir;
        }
    }
}

Using it is quite simple:

var enumerator = new EnumerateDirectory.EnumerateDirectory("D:\\", true);
var allPaths = enumerator.ToArray(); //very fast
enumerator.Dispose(); //discard Win32 handlers

foreach (string path in allPaths)
{ 
	//allPaths will consist of all files and sub-directories of D:\
	if (File.Exists(path))
	{
		/*
			Process a file
		*/
	}
	else 
	{
		/*
			Process a directory
		*/
	}
}

That’s it folks. I hope it helps!

GD Star Rating
loading...
[SOLVED] "System.UnauthorizedAccessException: Access to the path is denied" occured in DirectoryInfo.GetFiles() and Directory.GetFiles(), 3.0 out of 5 based on 1 rating

About Hardono

Hi, I'm Hardono. I am working as a Software Developer. I am working mostly in Windows, dealing with .NET, conversing in C#. But I know a bit of Linux, mainly because I need to keep this blog operational. I've been working in Logistics/Transport industry for more than 11 years.

No Comment

Add Your Comment