Created
March 3, 2016 16:29
-
-
Save treytomes/ecde10ca3132dfed167c to your computer and use it in GitHub Desktop.
List directories and check if a directory is empty using Kernel32 calls.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Imports System.IO | |
Imports System.Runtime.InteropServices | |
''' <remarks> | |
''' I don't think this is actually faster than the .NET Directory functions. | |
''' </remarks> | |
Public Class FileSystemHelper | |
Private Shared ReadOnly conInvalidHandleValue As IntPtr = New IntPtr(-1) | |
<Flags> | |
Private Enum FileAttributes | |
FILE_ATTRIBUTE_READONLY = 1 | |
FILE_ATTRIBUTE_HIDDEN = 2 | |
FILE_ATTRIBUTE_SYSTEM = 4 | |
FILE_ATTRIBUTE_DIRECTORY = 16 | |
FILE_ATTRIBUTE_ARCHIVE = 32 | |
FILE_ATTRIBUTE_DEVICE = 64 | |
FILE_ATTRIBUTE_NORMAL = 128 | |
FILE_ATTRIBUTE_TEMPORARY = 256 | |
FILE_ATTRIBUTE_SPARSE_FILE = 512 | |
FILE_ATTRIBUTE_REPARSE_POINT = 1024 | |
FILE_ATTRIBUTE_COMPRESSED = 2048 | |
FILE_ATTRIBUTE_OFFLINE = 4096 | |
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 8192 | |
FILE_ATTRIBUTE_ENCRYPTED = 16384 | |
FILE_ATTRIBUTE_INTEGRITY_STREAM = 32768 | |
FILE_ATTRIBUTE_VIRTUAL = 65536 | |
FILE_ATTRIBUTE_NO_SCRUB_DATA = 131072 | |
End Enum | |
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> | |
Private Structure WIN32_FIND_DATA | |
Public dwFileAttributes As UInteger | |
Public ftCreationTime As ComTypes.FILETIME | |
Public ftLastAccessTime As ComTypes.FILETIME | |
Public ftLastWriteTime As ComTypes.FILETIME | |
Public nFileSizeHighs As UInteger | |
Public nFileSizeLows As UInteger | |
Public dwReserved0s As UInteger | |
Public dwReserved1s As UInteger | |
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)> | |
Public cFileName As String | |
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=14)> | |
Public cAlternateFileName As String | |
End Structure | |
<DllImport("kernel32.dll", CharSet:=CharSet.Auto)> | |
Private Shared Function FindFirstFile(lpFileName As String, <Out> ByRef lpFindFileData As WIN32_FIND_DATA) As IntPtr | |
End Function | |
<DllImport("kernel32.dll", CharSet:=CharSet.Auto)> | |
Private Shared Function FindNextFile(hFindFile As IntPtr, <Out> ByRef lpFindFileData As WIN32_FIND_DATA) As Boolean | |
End Function | |
<DllImport("kernel32.dll", CharSet:=CharSet.Auto)> | |
Private Shared Function FindClose(hFindFile As IntPtr) As Boolean | |
End Function | |
Public Shared Iterator Function GetDirectories(pPath As String) As IEnumerable(Of String) | |
If String.IsNullOrEmpty(pPath) Then | |
Throw New ArgumentNullException(pPath) | |
End If | |
If Directory.Exists(pPath) Then | |
If Not pPath.EndsWith(Path.DirectorySeparatorChar.ToString()) Then | |
pPath &= Path.DirectorySeparatorChar | |
End If | |
Dim oFindData As WIN32_FIND_DATA = Nothing | |
Dim oFindHandle As IntPtr = FindFirstFile(pPath & "*", oFindData) | |
If oFindHandle <> conInvalidHandleValue Then | |
Try | |
Do | |
If (oFindData.cFileName <> "." AndAlso oFindData.cFileName <> "..") Then | |
If CBool(oFindData.dwFileAttributes And FileAttributes.FILE_ATTRIBUTE_DIRECTORY) Then | |
Yield pPath & oFindData.cFileName | |
End If | |
End If | |
Loop Until Not FindNextFile(oFindHandle, oFindData) | |
Finally | |
FindClose(oFindHandle) | |
End Try | |
End If | |
End If | |
End Function | |
Public Shared Function IsDirectoryEmpty(pPath As String) As Boolean | |
If String.IsNullOrEmpty(pPath) Then | |
Throw New ArgumentNullException(pPath) | |
End If | |
If Directory.Exists(pPath) Then | |
If Not pPath.EndsWith(Path.DirectorySeparatorChar.ToString()) Then | |
pPath &= Path.DirectorySeparatorChar | |
End If | |
Dim oFindData As WIN32_FIND_DATA = Nothing | |
Dim oFindHandle As IntPtr = FindFirstFile(pPath & "*", oFindData) | |
If oFindHandle <> conInvalidHandleValue Then | |
Try | |
Dim blnIsEmpty As Boolean = True | |
Do | |
If (oFindData.cFileName <> ".") AndAlso (oFindData.cFileName <> "..") Then | |
Exit Do | |
End If | |
Loop Until Not FindNextFile(oFindHandle, oFindData) | |
Return blnIsEmpty | |
Finally | |
FindClose(oFindHandle) | |
End Try | |
End If | |
Throw New Exception("Failed to get directory first file", Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error())) | |
End If | |
Throw New DirectoryNotFoundException() | |
End Function | |
End Class |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment