⚡️ Major speed boost for an updated example! 💻
🛠 Now featuring a multi wildcard filter for files like "*.exe/*.dll" with non-recursive searching.
🚫 Code updated to disable Wow64 redirection.
🏎 Leveraging Alessandro Cantatore's WildMatch routine for performance that's 4x faster than PathMatchSpec()!
🌐 Unicode support confirmed. ✅
#TechUpdate #Coding #Programmers #SoftwareDevelopment #PerformanceEnhancement #Unicode #Wow64 #ITNews 🚀🖥💾🔍♾️
---
'Multi wildcard filter, like "*.exe/*.dll".
'Pretty fast
'Non recursive.
'Code disable Wow64 redirection.
'Use of Alessandro Cantatore WildMatch routine wich is four times faster than PathMatchSpec().
'Unicode
'Etc...
#COMPILE EXE '#Win 10.04# 'José Roca includes compatible
#DIM ALL
%Unicode = 1
#INCLUDE "Win32Api.inc"
'_____________________________________________________________________________
FUNCTION FileTimeToInternationalDate(File_Time AS FileTime) AS WSTRING
LOCAL Local_File_Time AS FileTime
LOCAL Sys_Time AS SystemTime
FileTimeToLocalFileTime(File_Time, Local_File_Time) 'Convert (UTC) Universal Time Coordinate to local time
FileTimeToSystemTime(Local_File_Time, Sys_Time) 'Convert to SystemTime
'Make a human readable string date and time
FUNCTION = FORMAT$(Sys_Time.wYear, "0000") & "/" & FORMAT$(Sys_Time.wMonth, "00") & "/" & _
FORMAT$(Sys_Time.wDay, "00") & " " & FORMAT$(Sys_Time.wHour, "00") & ":" & _
FORMAT$(Sys_Time.wMinute, "00") & ":" & FORMAT$(Sys_Time.wSecond, "00") & "." & _
FORMAT$(Sys_Time.wMilliSeconds, "000") & " " & _
CHOOSE$(Sys_Time.wDayOfWeek + 1, "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")
END FUNCTION
'_____________________________________________________________________________
FUNCTION WildMatchAC7(BYVAL sString AS WSTRING, BYVAL sFilter AS WSTRING) AS LONG
'Validate data using wildard * ?
'(?) Any single character, (*) None or more character, 4 time faster than PathMatchSpec
'7th routine. C version by by Alessandro Cantatore. http://xoomer.virgilio.it/acantato/dev/wildcard/wildmatch.html#c_cpp_userjournal_algo
LOCAL pStringStart AS WORD POINTER
LOCAL pStringIndex AS WORD POINTER
LOCAL pFilterStart AS WORD POINTER
LOCAL pFilterIndex AS WORD POINTER
LOCAL Star AS LONG
pStringStart = STRPTR(sString) : pFilterStart = STRPTR(sFilter)
'CharLowerBuff(BYVAL pStringStart, LEN(sString)) : CharLowerBuff(BYVAL pFilterStart, LEN(sFilter)) 'For console
pStringIndex = pStringStart : pFilterIndex = pFilterStart
DO
IF @pStringIndex = 0 THEN EXIT DO
SELECT CASE @pFilterIndex
CASE 42 '(*)
Star = %TRUE
pStringStart = pStringIndex : pFilterStart = pFilterIndex
WHILE @pFilterStart = 42 '(*) For consecutive (*). While-wend may be removed if multi* is shrinked to single* before calling the function
INCR pFilterStart
WEND
IF @pFilterStart = 0 THEN FUNCTION = %TRUE : EXIT FUNCTION
pStringIndex = pStringStart : pFilterIndex = pFilterStart
ITERATE DO
CASE 63 '(?)
'Let it go
CASE ELSE
IF @pStringIndex <> @pFilterIndex THEN
IF star = 0 THEN EXIT FUNCTION
INCR pStringStart
pStringIndex = pStringStart : pFilterIndex = pFilterStart
ITERATE DO
END IF
END SELECT
INCR pStringIndex : INCR pFilterIndex
LOOP
WHILE @pFilterIndex = 42 '(*)
INCR pFilterIndex
WEND
IF @pFilterIndex = 0 THEN FUNCTION = %TRUE
END FUNCTION
'_____________________________________________________________________________
FUNCTION FileEnum(BYVAL sFolder AS WSTRING, BYVAL sFilter AS WSTRING, _
BYREF FileDataArray() AS WIN32_FIND_DATA) AS LONG
LOCAL FileData AS WIN32_FIND_DATA
LOCAL hFile AS DWORD
LOCAL hLib AS DWORD
LOCAL pProc AS DWORD
LOCAL uBoundSubFolder AS DWORD
LOCAL uBoundFileDataArray AS DWORD
LOCAL Wow64RedirectionVal AS DWORD
LOCAL SubFolderCount AS LONG
LOCAL FileCount AS LONG
LOCAL FilterIndex AS LONG
LOCAL FilterCount AS LONG
LOCAL index AS LONG
REDIM FileDataArray(0 TO 50000) AS WIN32_FIND_DATA
uBoundFileDataArray = UBOUND(FileDataArray())
DIM zSubFolder(0 TO 1000) AS WSTRINGZ * %MAX_PATH
uBoundSubFolder = UBOUND(zSubFolder)
'DO
' REPLACE "//" WITH "/" IN sFilter
'LOOP UNTIL INSTR(sFilter, "//") = 0
FilterCount = PARSECOUNT(sFilter, "/")
DIM sFilterArray(1 TO FilterCount) AS STRING
PARSE sFilter, sFilterArray(), "/"
FOR index = 1 TO FilterCount
sFilterArray(index) = TRIM$(sFilterArray(index))
NEXT
IF ASC(sFolder, - 1) <> 92 THEN sFolder = sFolder & "\"
'The following Wow64DisableWow64FsRedirection disable file system redirection
' so that a 32-bit application that is running under WOW64 can open
' the 64-bit version of files in %SystemRoot%\System32
' instead of being redirected to the 32-bit version in %SystemRoot%\SysWOW64.
'Disables file system redirection for the calling thread. File system redirection is enabled by default.
Wow64DisableWow64FsRedirection(Wow64RedirectionVal) 'Use with XPpro64, Vista, Server2003sp1, and newer
DO
hFile = FINDFIRSTFILE(sFolder & "*", FileData)
IF hFile <> %INVALID_HANDLE_VALUE THEN
DO
IF (FileData.dwFileAttributes AND %FILE_ATTRIBUTE_DIRECTORY) THEN 'It's a folder
IF ASC(FileData.cFileName, -1) <> 46 THEN 'Check for "." and "..", only those can end with a dot.
INCR SubFolderCount
IF SubFolderCount > uBoundSubFolder THEN
uBoundSubFolder = uBoundSubFolder + 1000
REDIM PRESERVE zSubFolder(0 TO uBoundSubFolder)
END IF
zSubFolder(SubFolderCount) = sFolder & FileData.cFileName & "\"
END IF
ELSE 'It's a file, have a cigar!
FOR FilterIndex = 1 TO FilterCount
'If .cFilename is SFN then .cAlternateFileName will be empty
'If .cFilename is LFN then .cAlternateFileName will contain SFN
IF WildMatchAC7(FileData.cFileName, sFilterArray(FilterIndex)) THEN 'Four time faster than PATHMATCHSPEC()
FileDataArray(FileCount) = FileData
FileDataArray(FileCount).cFileName = sFolder & FileData.cFileName
'Also available FileDataArray(FileCount).cAlternateFileName (Short filename)
'Also available FileDataArray(FileCount).dwFileAttributes
'Also available FileDataArray(FileCount).ftCreationTime
'Also available FileDataArray(FileCount).ftLastAccessTime
'Also available FileDataArray(FileCount).nFileSizeHigh
'Also available FileDataArray(FileCount).nFileSizeLow
INCR FileCount
IF FileCount > uBoundFileDataArray THEN
uBoundFileDataArray = uBoundFileDataArray + 50000
REDIM PRESERVE FileDataArray(0 TO uBoundFileDataArray)
END IF
EXIT FOR
END IF
NEXT
END IF
LOOP WHILE FINDNEXTFILE(hFile, FileData)
FINDCLOSE(hFile)
END IF
IF SubFolderCount = 0 THEN EXIT LOOP
sFolder = zSubFolder(SubFolderCount)
DECR SubFolderCount
LOOP
Wow64RevertWow64FsRedirection(Wow64RedirectionVal) 'Use with XPpro64, Vista, Server2003sp1, and newer
REDIM PRESERVE FileDataArray(FileCount)
FUNCTION = FileCount
END FUNCTION
'_____________________________________________________________________________
FUNCTION PBMAIN() AS LONG
DIM FileDataArray2(0 TO 0) AS WIN32_FIND_DATA
LOCAL sFolder AS WSTRING
LOCAL sFilter AS WSTRING
LOCAL sLog AS WSTRING
LOCAL TotalByte AS QUAD
LOCAL FileCount AS DWORD
LOCAL TimeStart AS DWORD
LOCAL index AS LONG
sFolder = "C:\" : sFilter = "*.exe/*.dll*"
'sFolder = "D:\" : sFilter = "*.bas/*.exe/*.rc"
TimeStart = GetTickCount()
FileCount = FileEnum(sFolder, sFilter, FileDataArray2()) '32 sec on first else .546
sLog = "Folder: " & $TAB & sFolder & $CRLF & "Filter: " & $TAB & sFilter & $CRLF & $CRLF
FOR index = 0 TO MIN(15, FileCount - 1)
sLog &= FORMAT$(index, "0000") & ") " & FileDataArray2(index).cFileName & $CRLF
TotalByte = TotalByte + MAK(QUAD, FileDataArray2(index).nFileSizeLow ,FileDataArray2(index).nFileSizeHigh)
NEXT
sLog &= "..." & $CRLF & $CRLF & FORMAT$((GetTickCount() - TimeStart) / 1000, "###,###.000") & " seconds elapsed" & $CRLF & $CRLF & _
"File count " & FORMAT$(FileCount - 1, "#,#") & _
$CRLF & $CRLF & "Total byte " & FORMAT$(TotalByte, "#,#") & $CRLF
MessageBox(%HWND_DESKTOP, (sLog), "FINDFIRS/NEXTTFILE", %MB_OK OR %MB_SYSTEMMODAL OR %MB_TOPMOST)
END FUNCTION
'_____________________________________________________________________________
'�