user2214609
user2214609

Reputation: 4951

Get all directories and catch permissions exception and continue

public void newestFile(string path)
{
    try
    {
        foreach (var item in dir.GetDirectories("*.*", SearchOption.AllDirectories))
        {
            var file = item.GetFiles().OrderByDescending(f => f.LastWriteTime).First();
        } 
    }
    catch (Exception ex)
    {

    }                     
}

I want to get the newest file from each directory from specific path and continue after catch the permission exception, currently my code stuck in catch and not continue.

Upvotes: 2

Views: 1071

Answers (2)

Matthew Watson
Matthew Watson

Reputation: 109547

Unfortunately Microsoft's implementation of GetDirectories() is extremely poor, and doesn't handle IO exceptions relating to access rights.

If you want to just skip over directories that you don't have access to (such as the special Recycle Bin folder, for example), then you have to write your own wrapper for the Windows API functions FindFirstFile() and FindNextFile().

Here's a complete example. If you run it, you'll see that it lists all the accessible directories on your C: drive.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using Microsoft.Win32.SafeHandles;

namespace Demo
{
    public class Program
    {
        private void run()
        {
            string root = "C:\\";

            foreach (var folder in FolderEnumerator.EnumerateFoldersRecursively(root))
                Console.WriteLine(folder);
        }

        private static void Main()
        {
            new Program().run();
        }
    }

    public static class FolderEnumerator
    {
        public static IEnumerable<string> EnumerateFoldersRecursively(string root)
        {
            foreach (var folder in EnumerateFolders(root))
            {
                yield return folder;

                foreach (var subfolder in EnumerateFoldersRecursively(folder))
                    yield return subfolder;
            }
        }

        public static IEnumerable<string> EnumerateFolders(string root)
        {
            WIN32_FIND_DATA findData;
            string spec = Path.Combine(root, "*");

            using (SafeFindHandle findHandle = FindFirstFile(spec, out findData))
            {
                if (!findHandle.IsInvalid)
                {
                    do
                    {
                        if ((findData.cFileName != ".") && (findData.cFileName != ".."))  // Ignore special "." and ".." folders.
                        {
                            if ((findData.dwFileAttributes & FileAttributes.Directory) != 0)
                            {
                                yield return Path.Combine(root, findData.cFileName);
                            }
                        }
                    }
                    while (FindNextFile(findHandle, out findData));
                }
            }
        }

        internal sealed class SafeFindHandle: SafeHandleZeroOrMinusOneIsInvalid
        {
            [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]

            public SafeFindHandle(): base(true)
            {
            }

            protected override bool ReleaseHandle()
            {
                if (!IsInvalid && !IsClosed)
                {
                    return FindClose(this);
                }

                return (IsInvalid || IsClosed);
            }

            protected override void Dispose(bool disposing)
            {
                if (!IsInvalid && !IsClosed)
                {
                    FindClose(this);
                }

                base.Dispose(disposing);
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct FILETIME
        {
            public uint dwLowDateTime;
            public uint dwHighDateTime;

            public long ToLong()
            {
                return dwLowDateTime + ((long)dwHighDateTime) << 32;
            }
        };

        [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]

        internal struct WIN32_FIND_DATA
        {
            public FileAttributes dwFileAttributes;
            public FILETIME       ftCreationTime;
            public FILETIME       ftLastAccessTime;
            public FILETIME       ftLastWriteTime;
            public int            nFileSizeHigh;
            public int            nFileSizeLow;
            public int            dwReserved0;
            public int            dwReserved1;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_PATH)]
            public string cFileName;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_ALTERNATE)]
            public string cAlternate;
        }

        [DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
        private static extern SafeFindHandle FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);

        [DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool FindNextFile(SafeHandle hFindFile, out WIN32_FIND_DATA lpFindFileData);

        [DllImport("kernel32.dll", SetLastError=true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool FindClose(SafeHandle hFindFile);

        private const int MAX_PATH = 260;
        private const int MAX_ALTERNATE = 14;
    }
}

Note: This code uses FindFirstFile() and FindNextFile() which iterate through all folders AND files. The code above is just ignoring the files and only returning the folders.

It would be more efficient to use FindFirstFileEx() and specify a flag to return only directories. I leave that change as the proverbial exercise for the reader. ;)

Upvotes: 4

King King
King King

Reputation: 63317

public string[] newestFile(string path){    
    IEnumerable<string> files = new string[]{};
    foreach (var item in dir.GetDirectories(Path.Combine(path,"*.*"), SearchOption.AllDirectories))
    {
       try {
        files = files.Concat(item.GetFiles().OrderByDescending(f => f.LastWriteTime).First());
       }
       catch {}
    }   
    return files.ToArray();  
}

Upvotes: 0

Related Questions