Enhanced file patterns in "Loop, Files"

Propose new features and changes
Haswell
Posts: 90
Joined: 21 Feb 2016, 17:11

Enhanced file patterns in "Loop, Files"

20 Nov 2020, 17:29

I would like to use asteriks in a filepath to define one level of a folder.
For example, I need to handle folders of all user.
I don't know how many users I have but I want to process all of them in one manner in one loop:

Code: Select all

loop, files, C:\Users\*\AppData\Local\SomeFolder\*.log, F
{
	OutputDebug, % A_LoopFileFullPath
}
Ideally, the idea could be extended to all other functions that make use of file patterns.
Last edited by Haswell on 21 Nov 2020, 04:52, edited 1 time in total.
User avatar
lmstearn
Posts: 694
Joined: 11 Aug 2016, 02:32
Contact:

Re: Enhanced file patterns in "Loop, Files"

21 Nov 2020, 04:43

Hi @Haswell ,
Nice wish, may not happen- but you never know. If the files are on NTFS drives, there's a modification from this script which should list the files you want:

Code: Select all

#NoEnv
#SingleInstance, force
SetBatchLines, -1
showprogress := 1
#MaxMem 256
NotepadWaitCount := 0
continueWait := 0
if not A_IsAdmin
{
	run *runAs "%A_ScriptFullPath%"  ; Requires v1.0.92.01+
	ExitApp
}
;MsgBox % RegExMatch("C:\Users\New\AppData\Local\Google\Chrome\User Data\Default\IndexedDB\https_www.greetingcardpoet.com_0.indexeddb.leveldb\000003.log", "i)(.*)local(.*)\.log$")  
; i): AHK's "break from tradition": https://www.autohotkey.com/docs/misc/RegEx-QuickRef.htm#Options
inputbox, s, ListMFTfiles, Folder [regex]`n(no spaces in regex), , 300, 140, , , , , % substr(A_WinDir, 1, 2) " US)(.*)\\AppData\\(.*)\\Local\\(.*)(.*)\.log$"
	If(ErrorLevel)
	ExitApp
t1 := A_TickCount
s := regExReplace(regExReplace(s, "^\s+", ""), "\s+$", "")
i := instr(s, " ", true, 0)
i := (i && FileExist(s)="") ? i : strlen(s) + 1
filelist := ListMFTfiles(regExReplace(substr(s, 1, i-1), "\s$", ""), substr(s, i + 1), "|", showprogress, num, 1000000)
	if (!filelist)
	{
			if (showprogress)
			{
			SetTimer, WaitForNotepad, Delete
			Progress, Off
			}
		msgbox Nothing found for %s%`nError code: %num%
		exitApp
	}

if( strlen(filelist)>1250000 )
{
	StringReplace, filelist, filelist, |, `n, all
	file := fileOpen(A_Temp "\MFTreader file list.txt", "w", "utf-8"), file.Write(filelist), file.close()
	Run, notepad "%A_Temp%\MFTreader file list.txt"
	Return
}


GuiControl, -Redraw, flChoice
gui, add, listbox, % "R" (num>30 ? 30 : num) " W700 vflChoice gflClick Multi", %filelist%
gui, add, button, default gflRunBtn, &Run
gui, add, button, % x + 10 "gflFolderBtn", &Folder
gui, add, button, % x + 10 "gflSellAllBtn", &Select all
gui, add, button, % x + 10 "gflCopyBtn", &Copy names
gui, add, button, % x + 10 "gflCancel", &Cancel
GuiControl, +Redraw, flChoice

	if (showprogress)
	{
	SetTimer, WaitForNotepad, Delete
	Progress, Off
	}

gui, show, autosize, % "ListMFTfiles: " num " files in " (A_TickCount-t1) "ms for " s

HotKey, ifWinActive, % "ahk_id " WinExist("A")
HotKey, Enter, flRunBtn
HotKey, ^Enter, flFolderBtn
HotKey, ^a, flSellAllBtn
HotKey, ^c, flCopyBtn
HotKey, ^Ins, flCopyBtn
HotKey, ^Insert, flCopyBtn
HotKey, Escape, flCancel
return

WaitForNotepad:
	If (WinExist("MFTreader file list.txt - Notepad"))
	{
	SetTimer, WaitForNotepad, Delete
		if (showProgress)
		Progress, Off
	exitapp
	}
	else
	{
		if (NotepadWaitCount < 35)
		{
		NotepadWaitCount++
			if (!continueWait)
			Progress, % 83 + NotepadWaitCount/2
		}
		else
		{
			if (filelist)
			{
			NotepadWaitCount++
				if (NotepadWaitCount > 150)
				{
					if (showProgress)
					Progress, Off

				msgbox, 8196 , Notepad?, The MFTreader file list in Notepad is not available. Continue Waiting?
					IfMsgBox, Yes
					{
					NotepadWaitCount := 0
					continueWait := 1
					}
					else
					{
					SetTimer, WaitForNotepad, Delete
					exitapp
					}
				}
			}
		}
	}
Return

#IfWinActive ListMFTfiles ahk_class #32770
flClick:
	IfEqual, A_GuiEvent, DoubleClick, goto flRunBtn
	return
flRunBtn:
	ControlGet, c, Choice, , ListBox1, A
	SplitPath, c, fname, fdir
	run, %c%, %fdir%, UseErrorLevel
	return
flFolderBtn:
	ControlGet, c, Choice, , ListBox1, A
	run, explorer /select`, "%c%", , UseErrorLevel
	return
flSellAllBtn:
	PostMessage, LB_SETSEL := 0x185, 1, -1, ListBox1, A
	return
flCopyBtn:
	gui, submit, nohide
	StringReplace, Clipboard, flChoice, |, `n, all
	return
^w::
flCancel:
	ExitApp
#IfWinActive
; path:
;	where to search, drive or fully specified folder, for example C:\folder
; regex:
;	search for file names that match regex, only file name is matched, default is none
; delim:
;	filelist delimiter, default is newline `n
; showprogress:
;	show minimal progressbar in screen center
; num:
;	variable that receives number of files returned or error status when trying to obtain:
;	-1, -2: root folder handle or info, -3, -4: path handle or info (To be done), -5,  Createfile root handle
;	 -6: Query Journal fail ,-7: volume handle or info, -8: USN journal handle
; plainSearchTimeout: (ms)
;	if greater than 0 (default), plain folder enumeration is used for no more than specified time.
;
; RETURN VALUE:
;	filelist or empty string if error occured (also see 'num' parameter)

ListMFTfiles(path, regex = "", delim = "`n", showProgress := 0, byref numF = "", plainSearchTimeout := 0)
{
; Fun fact: NTFS max files is 4,294,967,295  (2³² minus 1 file)
;Windows 2000 Change Journal Explained:  https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/bb742450(v=technet.10)
;Nfts Workings: https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc781134(v=ws.10)
;=== init
	t0 := A_TickCount
	drive := substr(path, 1, 2)
	path := (substr(path, 0)="\") ? path : path "\"

	OPEN_EXISTING := 3
	FILE_FLAG_BACKUP_SEMANTICS := 0x2000000
	SHARE_RW := 3 ;FILE_SHARE_READ | FILE_SHARE_WRITE
	GENERIC_RW := 0xC0000000 ;GENERIC_READ | GENERIC_WRITE
	DWORDLONG_SIZE := 8
	STATUS_SUCCESS := 1
	
;=== if path can be enumerated within specified time, return filelist at once
	if( plainSearchTimeout>0 )
	{

		numF := 0
		bUsePath := true
		VarSetCapacity(filelist, 1000 * 200) ; 1000 filepaths of ~100 widechars

			loop, %path%*, 1, 1 ;folders too, with recursion
				if(A_TickCount - t0 > plainSearchTimeout)
				{
				bUsePath := false
				break
				}
				else if(regex = "" || regExMatch(A_LoopFilePath, regex))
				{
				filelist .= A_LoopFileLongPath delim
				numF++
				}

			if(bUsePath)
			{
			VarSetCapacity(filelist, -1)
			Sort, filelist, D%delim%
			return filelist
			}
	}

;=== get root folder ("\") refnumber

	hRoot := dllCall("CreateFile", "wstr", "\\.\" drive "\", "uint", 0, "uint", SHARE_RW, "uint", 0
					, "uint", OPEN_EXISTING, "uint", FILE_FLAG_BACKUP_SEMANTICS, "uint", 0)
	if(hRoot = -1)
	{
		numF := -1
		return
	}
	;BY_HANDLE_FILE_INFORMATION
	;	0	DWORD dwFileAttributes;
	;	4	FILETIME ftCreationTime: DWORD Lodate DWORD Hidate
	;	12	FILETIME ftLastAccessTime; DWORD Lodate DWORD HIdate
	;	20	FILETIME ftLastWriteTime;
	;	28	DWORD dwVolumeSerialNumber;
	;	32	DWORD nFileSizeHigh;
	;	36	DWORD nFileSizeLow;
	;	40	DWORD nNumberOfLinks;
	;	44	DWORD nFileIndexHigh;
	;	48	DWORD nFileIndexLow;
	;	See note in DOCs:  Windows Server 2012 requires GetFileInformationByHandleEx for hRoot, which is 128 bits  on that system.
	;	Else it will not work on Windows Server 2012 running the Refs filesystem!
	VarSetCapacity(fi, 52, 0)

		if(dllCall("GetFileInformationByHandle", "uint", hRoot, "uint", &fi) != STATUS_SUCCESS)
		{
		dllCall("CloseHandle", "uint", hRoot)
		numF := -2
		return
		}
	dllCall("CloseHandle", "uint", hRoot)
	dirDict := {}
	refMax := ((numget(fi, 44)<<32) + numget(fi, 48)) ;nFileIndex: combined Lo Hi to get a 16 digit file identifier of root
	; The big one!
	dirDict[refMax] := {"name":drive, "parent":"0", "files":{}}


;=== open volume

	hJRoot := dllCall("CreateFile", "wstr", "\\.\" drive, "uint", GENERIC_RW, "uint", SHARE_RW, "uint", 0
				, "uint", OPEN_EXISTING, "uint", FILE_FLAG_SEQUENTIAL_SCAN := 0x08000000, "uint", 0)
		if(hJRoot = -1)
		{
		numF := -5
		return
		}

;=== open Update Sequence Number (USN) journal ("not to be confused with NTFS, a journaling file system which uses the NTFS Log ($LogFile) to record metadata changes to the volume")
; Ref https://blog.synsysit.com/smack-your-head-with-usn-journal-everything-you-ever-wanted-to-know-about-this-digital-forensic-artifact/

	; Not sure if the following works on pre NTFS 3.0 (introduced on Win2K)
	VarSetCapacity(cujd, 16) ;CREATE_USN_JOURNAL_DATA: cujd
	numput(0x800000, cujd, 0, "uint64") ;DWORDLONG: MaximumSize: target maximum size that the NTFS file system allocates for the change journal, in bytes
	numput(0x100000, cujd, 8, "uint64") ;DWORDLONG: AllocationDelta: size of memory allocation that is added to the end and removed from the beginning of the change journal, in bytes
	; FSCTL_* in this function supported in Windows Server 2012 only with a Cluster Shared Volume File System (CsvFS)
	; FSCTL_CREATE_USN_JOURNAL requires Admin privileges
	; cb receives a null ptr- it seems the documentation wants it there as a dummy.

		if(dllCall("DeviceIoControl", "uint", hJRoot, "uint", FSCTL_CREATE_USN_JOURNAL := 0x000900e7, "Ptr", &cujd, "uint", 16, "uint*", 0, "uint", 0, "uint*", cb, "Ptr", 0) != STATUS_SUCCESS)
		{
		dllCall("CloseHandle", "uint", hJRoot)
		numF := -6
		return
		}
/*
Common errors
ERROR_INVALID_FUNCTION
The specified volume does not support change journals.

ERROR_INVALID_PARAMETER
One or more parameters is invalid, for example, DeviceIoControl returns this error code if the handle supplied is not a volume handle.

ERROR_JOURNAL_DELETE_IN_PROGRESS
An attempt is made to read from, create, delete, or modify the journal while a journal deletion is in process, or an attempt is made to write a USN record while a journal deletion is in process.
*/


;=== estimate overall number of files

	;NTFS_VOLUME_DATA_BUFFER
	;	0	LARGE_INTEGER (unique) VolumeSerialNumber;
	;	8	LARGE_INTEGER NumberSectors;
	;	16	LARGE_INTEGER TotalClusters (used and free) ;
	;	24	LARGE_INTEGER FreeClusters;
	;	32	LARGE_INTEGER TotalReserved;
	;	40	DWORD         BytesPerSector;
	;	44	DWORD         BytesPerCluster (cluster factor);
	;	48	DWORD         BytesPerFileRecordSegment;
	;	52	DWORD         ClustersPerFileRecordSegment;
	;	56	LARGE_INTEGER MftValidDataLength (length of the master file table, in bytes);
	;	64	LARGE_INTEGER MftStartLcn (starting kogical cluster number of the master file table);
	;	72	LARGE_INTEGER Mft2StartLcn (starting logical cluster number of the master file table mirror);
	;	80	LARGE_INTEGER MftZoneStart (starting logical cluster number of the master file table zone);
	;	88	LARGE_INTEGER MftZoneEnd (ending logical cluster number of the master file table zone);
	VarSetCapacity(voldata, 96, 0)
	mftFiles := 0
	mftFilesMax := 0
	; see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/a5bae3a3-9025-4f07-b70d-e2247b01faa6
	; cb a pointer to a variable that receives the size of voldata, in bytes.
		
		if(dllCall("DeviceIoControl", "uint", hJRoot, "uint", FSCTL_GET_NTFS_VOLUME_DATA := 0x00090064, "int*", 0, "uint", 0, "Ptr", &voldata, "uint", 96, "uint*", cb, "Ptr", 0) = STATUS_SUCCESS)
		{
			if (cb = 96)
				if(i := numget(voldata, 48))
				mftFilesMax := numget(voldata, 56, "uint64")//i ;MftValidDataLength/BytesPerFileRecordSegment
		}
		else
		{
		numF := -7
		Return
		}
	/*
	Common errors
	STATUS_INVALID_PARAMETER

	0xC000000D

	The handle specified is not open.

	STATUS_VOLUME_DISMOUNTED

	0xC000026E

	The specified volume is no longer mounted.

	STATUS_BUFFER_TOO_SMALL

	0xC0000023
	*/

	;=== USN journal query

	;USN_JOURNAL_DATA_V0 returned in object ujd
	;USN_JOURNAL_DATA_V1 is not supported before Windows 8 and Windows Server 2012. USN_JOURNAL_DATA_V2 is not supported before Windows 8.1 and Windows Server 2012 R2.
	;	0	DWORDLONG UsnJournalID (The NTFS file system uses this current journal identifier for an integrity check)
	;	8	USN FirstUsn (number of first record that can be read from the journal)
	;	16	USN NextUsn (number of next record to be written to the journal)
	;	24	USN LowestValidUsn (First record written into the journal for this journal instance)
	;	32	USN MaxUsn (The largest USN that the change journal supports.)
	;	40	DWORDLONG MaximumSize (target maximum size for the change journal, in bytes)
	;	48	DWORDLONG AllocationDelta (number of bytes of disk memory added to the end and removed from the beginning of the change journal each time memory is allocated or deallocated)
	;	V1
	;	56	WORD MinSupportedMajorVersion (minimum supported version of the USN change journal supported by the filesystem)
	;	58	WORD MaxSupportedMajorVersion (maximum supported version of the USN change journal supported by the filesystem)
	;	V2
	;	60	DWORD Flags (A toggle: FLAG_USN_TRACK_MODIFIED_RANGES_ENABLE := 0x00000001 Range tracking is turned on for the volume, 0 otherwise)
	;	64	DWORDLONG RangeTrackChunkSize (granularity of tracked ranges, valid when flags above := 1)
	;	72	LONGLONG RangeTrackFileSizeThreshold (File size threshold to start tracking range for files with equal or larger size, valid when flags above := 1)
	VarSetCapacity(ujd, 56, 0)
	; cb a pointer to a variable that receives the size of ujd, in bytes.
		if( dllCall("DeviceIoControl", "uint", hJRoot, "uint", FSCTL_QUERY_USN_JOURNAL := 0x000900f4, "uint*", 0, "uint", 0, "Ptr", &ujd, "uint", 56, "uint*", cb, "Ptr", 0) != STATUS_SUCCESS)
		{
		dllCall("CloseHandle", "uint", hJRoot)
		numF := -8
		return
		}
/*
Common errors
ERROR_INVALID_FUNCTION
The specified volume does not support change journals. Where supported, change journals can also be deleted.

ERROR_INVALID_PARAMETER
One or more parameters is invalid.

For example, DeviceIoControl returns this error code if the handle supplied is not a volume handle.

ERROR_JOURNAL_DELETE_IN_PROGRESS
An attempt is made to read from, create, delete, or modify the journal while a journal deletion is in process, or an attempt is made to write a USN record while a journal deletion is in process.

ERROR_JOURNAL_NOT_ACTIVE
An attempt is made to write a USN record or to read the change journal while the journal is inactive.

*/

	JournalMaxSize := numget(ujd, 40, "uint64") + numget(ujd, 48, "uint64") ;MaximumSize + AllocationDelta
	JournalChunkSize := 0x100000 ;1MB chunk, ~10-20 read ops for 150k files
		if(!mftFilesMax) ; then get an estimate (which might impact performance a little)
		mftFilesMax := JournalMaxSize/JournalChunkSize ;

	t1 := A_TickCount
		if showprogress
		Progress, b p0

;=== enumerate USN journal

	cb := 0
	numF := 0
	numD := 0
	VarSetCapacity(pData, DWORDLONG_SIZE + JournalChunkSize, 0)
	dirDict.SetCapacity(JournalMaxSize//(128 * 50)) ;average file name ~64 widechars, dircount is ~1/50 of filecount. dirDict[refMax] is preserved, of course

	;MFT_ENUM_DATA for med.
	;	0	DWORDLONG StartFileReferenceNumber (ordinal position within the files on the current volume at which the enumeration is to begin);
	;	8	USN LowUsn (lower bounds of range of USN values used to filter which records are returned);
	;	16	USN HighUsn(upper bounds of range of USN values used to filter which files are returned);
	;	V1 (Only for Windows Server 2012)
	;	24	WORD MinMajorVersion (minimum supported major version for the USN change journal)
	;	26	WORD MaxMajorVersion (maximum supported major version for the USN change journal: 2 or 3 dependent on USN_RECORD_V2 or USN_RECORD_V3)
	VarSetCapacity(med, 24, 0)
	numput(numget(ujd, 16, "uint64"), med, 16, "uint64") ;med.HighUsn=ujd.NextUsn
		; Outer loop is through JournalChunkSize. cb a pointer to a variable that receives the size of med, in bytes.
		while(dllCall("DeviceIoControl", "uint", hJRoot, "uint", FSCTL_ENUM_USN_DATA := 0x000900b3, "Ptr", &med, "uint", 24, "Ptr", &pData, "uint", DWORDLONG_SIZE + JournalChunkSize, "uint*", cb, "Ptr", 0))
		{

/*
Common errors

ERROR_INVALID_FUNCTION
The file system on the specified volume does not support this control code.

ERROR_INVALID_PARAMETER
One or more parameters is invalid e.g. handle supplied is not a volume handle.
*/
		t1a := A_TickCount
			if showprogress
			Progress, % (mftFiles*82)//mftFilesMax

		pUSN := &pData + DWORDLONG_SIZE ; &pData: A pointer to the output buffer that ***receives a USN*** followed by zero or more USN_RECORD_V2 or USN_RECORD_V3 structures so...
										; The USN first received may not be the same as the USN in following the USN_RECORD structure. A USN is DWORDLONG.
			while(cb>DWORDLONG_SIZE) ;cb decrements by USN.RecordLength as pUSN increments by USN.RecordLength
			{
			mftFiles++
			; 	USN_RECORD_COMMON_HEADER applies to USN_RECORD_V2, USN_RECORD_V3 and USN_RECORD_V4
			;	0	DWORD RecordLength (total length of a record, in bytes);
			;	4	WORD   MajorVersion (major version number of the change journal software for this record, here it's 3);
			;	6	WORD   MinorVersion (minor version number of the change journal software for this record);
			
			;	USN_RECORD V2 (XP & Server 2003)... (V3 (Win8+ & Win Server 2012) looks like this structure- but FileReferenceNumber & ParentFileReferenceNumber are 128 bit)
			;	https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/d2a2b53e-bf78-4ef3-90c7-21b918fab304
			;	8	DWORDLONG FileReferenceNumber (64 bit ordinal number of the file or directory for which this record notes changes);
			;	16	DWORDLONG ParentFileReferenceNumber (64-bit ordinal number of the directory where the file or directory that is associated with this record is located);
			;	24	USN Usn (USN of this record);
			;	32	LARGE_INTEGER TimeStamp (standard UTC time stamp (FILETIME) of this record, in 64-bit format.);
			;	40	DWORD Reason ( flags that identify reasons for changes that have accumulated in this file or directory journal record since the file or directory opened see: https://docs.microsoft.com/en-us/windows/win32/api/winioctl/ns-winioctl-usn_record_v3);
			;	44	DWORD SourceInfo (Additional info on the source of the change, set by the FSCTL_MARK_HANDLE of the DeviceIoControl operation);
			;	48	DWORD SecurityId (unique security identifier assigned to the file or directory associated with this record);
			;	52	DWORD FileAttributes (attributes for the file or directory associated with this record, as returned by the GetFileAttributes);
			;	56	WORD   FileNameLength (length of the name of the file or directory associated with this record, in bytes);
			;	58	WORD   FileNameOffset ( offset of the FileName member from the beginning of the structure.);
			;	60	WCHAR FileName[1] (name of the file or directory associated with this record in Unicode format. This file or directory name is of variable length);
			;	USN_RECORD_V4 record is only output when range tracking is turned on. Suitable tor Win8.1+, the structure varies from the above e.g. TimeStamp
			fnsize := numget(pUSN + 56, "ushort")
			fname := strget(pUSN + 60, fnsize//2, "UTF-16")
			isdir := numget(pUSN + 52) & 0x10 ;USN.FileAttributes & FILE_ATTRIBUTE_DIRECTORY
			ref := numget(pUSN + 8, "uint64") ;USN.FileReferenceNumber
			refparent := numget(pUSN + 16, "uint64") ;USN.ParentFileReferenceNumber

				if(isdir)
				{
				v := dirDict[ref]
					if(v = "") ;Not populated yet
					{
					v := {}
					v.files := {}
					}
				v.setCapacity(4) ;MaxItems: 4th value 'dir' is created later in resolveFolder()
				v.setCapacity("name", fnsize), v.name := fname
				v.setCapacity("parent", strlen(refparent)), v.parent := refparent
				; "Windows computes the file reference number as follows: 48 bits are the index of the file's primary record in the master file table (MFT), and the other 16 bits are a sequence number"
				; The following bit shift will fail for nested directories of > Some_To_be_Tested_Value (20 at least). If the bits in a refparent are joined, its length looks to be pretty much the same irrespective of its distance from Root.
				;v.setCapacity("parent", strlen(refparent)<<1), v.parent := refparent
				dirDict[ref] := v
				numD++
				}
				else
				{
					if(regex = "" || regExMatch(fname, regex))
					{
					v := dirDict[refparent]
						if(v = "")
						{
						v := {}
						dirDict[refparent] := {"files":v}
						}
						else
						v := v.files

					; 3rd value of v
					v.SetCapacity(ref, fnsize), v[ref] := fname
					numF++
					}
				}
			
			; Numget: "Do not pass a variable reference if the variable contains the target address; in that case, pass an expression such as MyVar+0"
			i := numget(pUSN + 0) ;USN.RecordLength
			pUSN += i
			cb -= i
			}

		nextUSN := numget(pData, "uint64")
		numput(nextUSN, med, "uint64")

		t1b += A_TickCount - t1a
		}

	dllCall("CloseHandle", "uint", hJRoot)

	t2 := A_TickCount
		if showprogress
		{
		Progress, 83

		SetTimer, WaitForNotepad, 30
		SetTimer, WaitForNotepad, , 2147483647
		}



;=== connect files to parent folders & build new cache
	VarSetCapacity(filelist, numF*200) ;average full filepath ~100 widechars
	bPathFilter := strlen(path) > 3 && instr(FileExist(path), "D")>0
	numF := 0
	if (bPathFilter)
	{
	for dk, dv in dirDict
		if(dv.files.getCapacity())
		{
			dir := _ListMFTfiles_resolveFolder(dirDict, dk)
			if(instr(dir, path) = 1)
				for k, v in dv.files
				filelist .= dir v delim, numF++
		}
	}
	else
	for dk, dv in dirDict
		if(dv.files.getCapacity())
		{
			dir := _ListMFTfiles_resolveFolder(dirDict, dk)
				for k, v in dv.files
				filelist .= dir v delim, numF++
		}

	dirDict=
	VarSetCapacity(filelist, -1)

	t3:=A_TickCount
;=== sort
	Sort, filelist, D%delim%


	t4:=A_TickCount
	;msgbox % "init`tenum`twinapi`tconnect`tsort`ttotal, ms`n" (t1-t0) "`t" t1b "`t" (t2-t1-t1b) "`t" (t3-t2) "`t" (t4-t3) "`t" (t4-t0) "`n`ndirs:`t" numD "`nfiles:`t" numF
	return filelist
	}

_ListMFTfiles_resolveFolder(byref dirDict, byref ddref)
{
	p := dirDict[ddref], pd := p.dir
	if(!pd)
	{
		pd := (p.parent ? _ListMFTfiles_resolveFolder(dirDict, p.parent) : "") p.name "\"
		p.setCapacity("dir", strlen(pd )* 2) ; wchar_t
		p.dir := pd
	}
	return pd
}
Necro edit: This script somehow magically worked when posted, doesn't appear to any more, with the path in the regex failing. The linked thread has been updated with a better version, however.
Last edited by lmstearn on 30 May 2022, 08:05, edited 1 time in total.
:arrow: itros "ylbbub eht tuO kaerB" a ni kcuts m'I pleH
iPhilip
Posts: 819
Joined: 02 Oct 2013, 12:21

Re: Enhanced file patterns in "Loop, Files"

13 Feb 2021, 14:12

Haswell wrote:
20 Nov 2020, 17:29
I would like to use asteriks in a filepath to define one level of a folder.
For example, I need to handle folders of all user.
I don't know how many users I have but I want to process all of them in one manner in one loop:

Code: Select all

loop, files, C:\Users\*\AppData\Local\SomeFolder\*.log, F
{
	OutputDebug, % A_LoopFileFullPath
}
Ideally, the idea could be extended to all other functions that make use of file patterns.
Hi @Haswell,

Interesting request. It seems easy enough to do it using the built-in function. See below.

Code: Select all

Loop, Files, C:\Users\*, D
   Loop, Files, %A_LoopFileFullPath%\AppData\Local\SomeFolder\*.log, F
      OutputDebug, % A_LoopFileFullPath
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)

Return to “Wish List”

Who is online

Users browsing this forum: No registered users and 51 guests