Saturday, July 2, 2022

#1 2021-12-14 01:18:51 am

test123testa
Member
Registered: 2021-11-18
Posts: 6

How do i iterate through every file including folders?

I am making a simple app that will loop through every file and subfolder in that folder, making a tree. I have made no code. The script should get a folder, then loop through every file in that folder,then with any folders in that folder, use that as the parameter for the next loop. I have no idea of how to start on this.

Offline

 

#2 2021-12-16 08:34:32 am

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 1369

Re: How do i iterate through every file including folders?

test123testa. It's not clear to me precisely how you want the script to work. The following returns each folder followed by the files in that folder. It uses the Finder, which can be slow or even fail if the number of folders and files is very large, although it was reasonably quick with a test folder containing 518 folders and files (0.9 second timed with Script Geek).

Applescript:

set folderTree to getFolderTree()

on getFolderTree()
   set theFolder to (choose folder)
   set folderTree to {theFolder as text}
   
   tell application "Finder"
       set theFiles to (name of every file in theFolder)
       if theFiles ≠ {} then set the end of folderTree to theFiles
       
       try
           set theFolders to (every folder of the entire contents of theFolder) as alias list
       on error
           display alert "No folders were found in the selected folder"
           error number -128
       end try
       
       repeat with aFolder in theFolders
           set contents of aFolder to aFolder as text
       end repeat
       set theFolders to sortFolders(theFolders) of me -- disable to change folder sort
       
       repeat with aFolder in theFolders
           set end of folderTree to linefeed & aFolder
           set theFiles to name of every file in folder aFolder
           if theFiles ≠ {} then set the end of folderTree to theFiles
       end repeat
   end tell
   
   set {ATID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, linefeed}
   set folderTree to folderTree as text
   set AppleScript's text item delimiters to ATID
   return folderTree
end getFolderTree

on sortFolders(a)
   repeat with i from (count a) to 2 by -1
       repeat with j from 1 to i - 1
           if item j of a > item (j + 1) of a then
               set {item j of a, item (j + 1) of a} to {item (j + 1) of a, item j of a}
           end if
       end repeat
   end repeat
   return a
end sortFolders

An example of the output is:

"Macintosh HD:Users:Robert:Working:
New Text File 1.txt
New Text File 2.txt

Macintosh HD:Users:Robert:Working:Folder 1A:
New Text File 1.txt

Macintosh HD:Users:Robert:Working:Folder 1A:Folder 2A:

Macintosh HD:Users:Robert:Working:Folder 1A:Folder 2A:Folder 3A:
New Text File 1.txt
New Text File 2.txt

Macintosh HD:Users:Robert:Working:Folder 1B:

Macintosh HD:Users:Robert:Working:Folder 1B:Folder 2B:
New Text File 1.txt"

Last edited by peavine (2021-12-17 08:07:08 am)


2018 Mac mini - macOS Monterey - Script Debugger 8

Offline

 

#3 2021-12-16 11:54:59 am

estockly
Member
Registered: 2009-01-03
Posts: 51

Re: How do i iterate through every file including folders?

I am making a simple app that will loop through every file and subfolder in that folder, making a tree. I have made no code. The script should get a folder, then loop through every file in that folder,then with any folders in that folder, use that as the parameter for the next loop. I have no idea of how to start on this.



This could be done with a single command using Shane's FileManagerLib script library.

Applescript:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

use script "FileManagerLib" version "2.3.4"
set setFolderTree to objects of (ChooseFolder) ¬
   searching subfolders true ¬
   include invisible items false ¬
   include folders true ¬
   include files false ¬
   result type files list

Freeware
https://latenightsw.com/freeware/
FileManagerLib v2.3.5

FileManagerLib provides commands for file management tasks like duplicating, copying, moving, renaming, deleting, and trashing files, as well as creating folders and alias files, getting the contents and entire contents of folders, and sorting lists of files. Version 2.3.x adds comparison commands and commands for dealing with date properties. (updated May 27, 2020)

Offline

 

#4 2021-12-18 03:04:23 pm

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 1369

Re: How do i iterate through every file including folders?

I rewrote my script in post 2 using ASObjC. This script is both faster and more reliable, and it writes the data to a text file on the desktop.

Applescript:

-- revised 2022.06.25

use framework "Foundation"
use scripting additions

on main()
   set theFolder to POSIX path of (choose folder)
   set theFolder to current application's |NSURL|'s fileURLWithPath:theFolder
   try
       set theFolders to getFolders(theFolder)
       set folderTree to getFolderTree(theFolders)
   on error
       display alert "An error has occurred" message "An item in the selected folder could not be processed" as critical
       error number -128
   end try
   saveFolderTree(folderTree, theFolder)
end main

on getFolders(theFolder)
   set fileManager to current application's NSFileManager's defaultManager()
   set theKeys to {current application's NSURLIsDirectoryKey, current application's NSURLIsPackageKey}
   set folderContents to (fileManager's enumeratorAtURL:theFolder includingPropertiesForKeys:theKeys options:6 errorHandler:(missing value))'s allObjects()
   
   set theFolders to current application's NSMutableArray's new()
   (theFolders's addObject:theFolder)
   repeat with anItem in folderContents
       set {theResult, isDirectory} to (anItem's getResourceValue:(reference) forKey:(current application's NSURLIsDirectoryKey) |error|:(missing value))
       if isDirectory as boolean is true then
           set {theResult, isPackage} to (anItem's getResourceValue:(reference) forKey:(current application's NSURLIsPackageKey) |error|:(missing value))
           if isPackage as boolean is false then (theFolders's addObject:anItem)
       end if
   end repeat
   
   set theDescriptor to current application's NSSortDescriptor's sortDescriptorWithKey:"path" ascending:true selector:"localizedStandardCompare:"
   return (theFolders's sortedArrayUsingDescriptors:{theDescriptor})
end getFolders

on getFolderTree(theFolders)
   set fileManager to current application's NSFileManager's defaultManager()
   set folderTree to current application's NSMutableArray's new()
   repeat with aFolder in theFolders
       set folderString to current application's NSString's stringWithFormat_("%@%@", linefeed, (aFolder as text))
       (folderTree's addObject:folderString)
       (folderTree's addObjectsFromArray:getFiles(aFolder, theFolders, fileManager))
   end repeat
   return text 2 thru -1 of ((folderTree's componentsJoinedByString:linefeed) as text)
end getFolderTree

on getFiles(theFolder, theFolders, fileManager)
   set theFiles to (fileManager's contentsOfDirectoryAtURL:theFolder includingPropertiesForKeys:{} options:4 |error|:(missing value))'s mutableCopy()
   theFiles's removeObjectsInArray:theFolders
   return ((theFiles's valueForKey:"lastPathComponent")'s sortedArrayUsingSelector:"localizedStandardCompare:")
end getFiles

on saveFolderTree(theText, theFolder)
   set theFolder to theFolder's lastPathComponent
   set fileName to theFolder's stringByAppendingString:" Folder Contents.txt"
   set theFile to (current application's NSHomeDirectory()'s stringByAppendingPathComponent:"Desktop")'s stringByAppendingPathComponent:fileName
   (current application's NSString's stringWithString:theText)'s writeToFile:theFile atomically:true encoding:(current application's NSUTF8StringEncoding) |error|:(missing value)
end saveFolderTree

main()

Last edited by peavine (2022-06-25 08:13:59 am)


2018 Mac mini - macOS Monterey - Script Debugger 8

Offline

 

#5 2021-12-19 09:18:37 pm

test123testa
Member
Registered: 2021-11-18
Posts: 6

Re: How do i iterate through every file including folders?

peavine wrote:

test123testa. It's not clear to me precisely how you want the script to work. The following returns each folder followed by the files in that folder. It uses the Finder, which can be slow or even fail if the number of folders and files is very large, although it was reasonably quick with a test folder containing 518 folders and files (0.9 second timed with Script Geek).

Applescript:

set folderTree to getFolderTree()

on getFolderTree()
   set theFolder to (choose folder)
   set folderTree to {theFolder as text}
   
   tell application "Finder"
       set theFiles to (name of every file in theFolder)
       if theFiles ≠ {} then set the end of folderTree to theFiles
       
       try
           set theFolders to (every folder of the entire contents of theFolder) as alias list
       on error
           display alert "No folders were found in the selected folder"
           error number -128
       end try
       
       repeat with aFolder in theFolders
           set contents of aFolder to aFolder as text
       end repeat
       set theFolders to sortFolders(theFolders) of me -- disable to change folder sort
       
       repeat with aFolder in theFolders
           set end of folderTree to linefeed & aFolder
           set theFiles to name of every file in folder aFolder
           if theFiles ≠ {} then set the end of folderTree to theFiles
       end repeat
   end tell
   
   set {ATID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, linefeed}
   set folderTree to folderTree as text
   set AppleScript's text item delimiters to ATID
   return folderTree
end getFolderTree

on sortFolders(a)
   repeat with i from (count a) to 2 by -1
       repeat with j from 1 to i - 1
           if item j of a > item (j + 1) of a then
               set {item j of a, item (j + 1) of a} to {item (j + 1) of a, item j of a}
           end if
       end repeat
   end repeat
   return a
end sortFolders

An example of the output is:

"Macintosh HD:Users:Robert:Working:
New Text File 1.txt
New Text File 2.txt

Macintosh HD:Users:Robert:Working:Folder 1A:
New Text File 1.txt

Macintosh HD:Users:Robert:Working:Folder 1A:Folder 2A:

Macintosh HD:Users:Robert:Working:Folder 1A:Folder 2A:Folder 3A:
New Text File 1.txt
New Text File 2.txt

Macintosh HD:Users:Robert:Working:Folder 1B:

Macintosh HD:Users:Robert:Working:Folder 1B:Folder 2B:
New Text File 1.txt"



Thats what i need, but it freezes up Finder.

AppleScript: 2.10
Browser: Firefox 95.0
Operating System: macOS 10.13

Offline

 

#6 2021-12-20 08:08:16 am

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 1369

Re: How do i iterate through every file including folders?

test123testa wrote:

Thats what i need, but it freezes up Finder.

AppleScript: 2.10
Browser: Firefox 95.0
Operating System: macOS 10.13



There are a number of reasons why the Finder script might fail, and it's impossible to identify the exact reason based on the information you provide. I only encountered an issue with this script when the number of folders and files being processed was large, which is the reason I provided the ASObjC script.

Just as an aside, it would appear that either the macOS or AppleScript versions shown in your post may not be correct. Perhaps you have mistaken Script Editor version for AppleScript version.

Last edited by peavine (2021-12-20 10:00:29 am)


2018 Mac mini - macOS Monterey - Script Debugger 8

Offline

 

#7 2021-12-20 06:49:22 pm

test123testa
Member
Registered: 2021-11-18
Posts: 6

Re: How do i iterate through every file including folders?

peavine wrote:
test123testa wrote:

Thats what i need, but it freezes up Finder.

AppleScript: 2.10
Browser: Firefox 95.0
Operating System: macOS 10.13



There are a number of reasons why the Finder script might fail, and it's impossible to identify the exact reason based on the information you provide. I only encountered an issue with this script when the number of folders and files being processed was large, which is the reason I provided the ASObjC script.

Just as an aside, it would appear that either the macOS or AppleScript versions shown in your post may not be correct. Perhaps you have mistaken Script Editor version for AppleScript version.



The OS version number is correct as i am running this script on a uni-book white mid-2010, but how do i get the applescript version? I do not want to use ASObjC.

Model: MacBook (13-inch, Mid 2010)
AppleScript: 2.10
Browser: Firefox 95.0
Operating System: macOS 10.13

Offline

 

#8 2021-12-20 07:20:16 pm

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 1369

Re: How do i iterate through every file including folders?

test123testa wrote:

The OS version number is correct as i am running this script on a uni-book white mid-2010, but how do i get the applescript version? I do not want to use ASObjC.

Model: MacBook (13-inch, Mid 2010)
AppleScript: 2.10
Browser: Firefox 95.0
Operating System: macOS 10.13



To get the AppleScript version, load Script Editor and select Script Editor > About, which will show both the Script Editor and AppleScript versions. The AppleScript version will probably be 2.5 or 2.6.

Based on the information you have provided, it is not possible for me to know why the Finder script doesn't work for you. I've tested and retested the script and it works fine, except when the number of folders and files is too great for Finder to handle. Perhaps another forum member will be able to help.


2018 Mac mini - macOS Monterey - Script Debugger 8

Offline

 

#9 2021-12-21 07:26:46 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 5530

Re: How do i iterate through every file including folders?

Hi.

This works quite well in Mojave:

Applescript:

main()

on main()
   set folderPath to (choose folder) as text
   set outputText to getFolderTree(folderPath)
   set fRef to (open for access file ((path to desktop as text) & "Folder Contents.txt") with write permission)
   try
       set eof fRef to 0
       write outputText to fRef as «class utf8»
       close access fRef
       display dialog "Listing saved to file \"Folder Contents.txt\" on desktop." buttons {"OK"} default button 1 with icon note
   on error msg number num
       close access fRef
       display dialog msg buttons {"OK"} default button 1
       error number n
   end try
end main

on getFolderTree(folderPath)
   script o
       property output : {}
       
       on recurse(folderHFSPath)
           -- Store the current folder path (hopefully in HFS format).
           set end of my output to folderHFSPath
           -- Get the POSIX paths of any subfolders and the names of any files.
           tell application "System Events"
               set thisFolder to folder folderHFSPath
               set subfolderPOSIXPaths to POSIX path of thisFolder's folders
               set fileNames to name of thisFolder's files
           end tell
           
           -- Sort the file names and concatenate them to the output.
           ShellSort(fileNames, 1, -1)
           set output to output & fileNames
           set end of my output to "" -- Empty line after last file name.
           
           -- Sort the subfolder paths and deal with them recursively.
           ShellSort(subfolderPOSIXPaths, 1, -1)
           repeat with POSIXPath in subfolderPOSIXPaths
               set POSIXPath to POSIXPath's contents
               -- Get the HFS path from a System Events folder object specified using this POSIX path!
               -- (Workaround for a filing system bug.)
               tell application "System Events" to set HFSPath to path of folder POSIXPath
               recurse(HFSPath)
           end repeat
       end recurse
   end script
   
   -- Call the recursive handler above.
   o's recurse(folderPath)
   -- Zap any names or paths beginning with ".".
   repeat with i from 1 to (count o's output)
       set thispath to item i of o's output
       if (thispath begins with ".") then set item i of o's output to missing value
   end repeat
   
   -- Return what's left as a single text with linefeeds.
   return join(o's output's text, linefeed)
end getFolderTree

(* Shell sort
Algorithm: Donald Shell, 1959.
AppleScript implementation: Nigel Garvey, 2010. *)

on ShellSort(theList, rangeIndex1, rangeIndex2)
   script o
       property lst : theList
   end script
   
   set listLen to (count theList)
   if (listLen > 1) then
       if (rangeIndex1 < 0) then set rangeIndex1 to listLen + rangeIndex1 + 1
       if (rangeIndex2 < 0) then set rangeIndex2 to listLen + rangeIndex2 + 1
       if (rangeIndex1 > rangeIndex2) then
           set {rangeLeft, rangeRight} to {rangeIndex2, rangeIndex1}
       else
           set {rangeLeft, rangeRight} to {rangeIndex1, rangeIndex2}
       end if
       
       set stepSize to (rangeRight - rangeLeft + 1) div 2
       repeat while (stepSize > 0)
           repeat with traversalIndex from (rangeLeft + stepSize) to rangeRight
               set currentValue to o's lst's item traversalIndex
               repeat with insertionIndex from (traversalIndex - stepSize) to rangeLeft by -stepSize
                   tell o's lst's item insertionIndex
                       if (it > currentValue) then
                           set o's lst's item (insertionIndex + stepSize) to it
                       else
                           set insertionIndex to insertionIndex + stepSize
                           exit repeat
                       end if
                   end tell
               end repeat
               if (insertionIndex < traversalIndex) then set o's lst's item insertionIndex to currentValue
           end repeat
           set stepSize to (stepSize / 2.2) as integer
       end repeat
   end if
   
   return -- nothing.
end ShellSort

on join(lst, delim)
   set astid to AppleScript's text item delimiters
   set AppleScript's text item delimiters to delim
   set txt to lst as text
   set AppleScript's text item delimiters to astid
   return txt
end join

Last edited by Nigel Garvey (2021-12-27 04:23:33 pm)


NG

Offline

 

#10 2021-12-21 07:54:12 am

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 1369

Re: How do i iterate through every file including folders?

Nigel. I tested your script, and it works great. I ran some timing tests with my test folder, and my ASObjC script was marginally faster, but the difference is not significant. Your script does throw an error when the target folder is my home folder.

System Events got an error: Can’t get folder "Macintosh HD:Users:Robert:Library:Containers:com.apple.AppleMediaServicesUI.SpyglassPurchases:Data:file:"


2018 Mac mini - macOS Monterey - Script Debugger 8

Offline

 

#11 2021-12-21 09:53:07 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 5530

Re: How do i iterate through every file including folders?

Hi peavine.

Thanks for testing my effort.

I suspect the relative speeds depend on the system and/or distribution of files and folders in the hierarchy. On my own machine so far, my script's faster than the ASObjC one (rather a surprise!) and they're both faster in Script Editor than in Script Debugger.

Neither of them can handle my own home folder!  lol  Mine goes on forever and eventually beachballs. Yours throws a "Can’t make some data into the expected type." error after about half a minute (or a minute-and-a-half in SD), the whole of the repeat loop in getFiles() being highlighted. I've trapped the error and ascertained that 'anItem' is a 'missing value' when the error occurs, but haven't backtracked further to find out why. I'm guessing it's something to do with the convoluted system of aliases that goes on in some of the Library subfolders.


NG

Offline

 

#12 2021-12-21 10:28:13 am

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 1369

Re: How do i iterate through every file including folders?

Thanks Nigel for all the information. This has been an interesting thread.

I had timed our scripts in Script Geek, and I'm surprised by the differing results reported by Script Editor and Script Debugger. With this type of script, I suspect timing results within a reasonable range are not very important.

It's unfortunate that my ASObjC script wouldn't run on your computer's home folder, as a user might want to do this on occasion. However, I've spent enough time on this thread, and the OP has no interest in the ASObjC script, so I'll leave things as they are.


2018 Mac mini - macOS Monterey - Script Debugger 8

Offline

 

#13 2021-12-22 03:54:15 am

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 5530

Re: How do i iterate through every file including folders?

Hi peavine.

I understand. I'm not inclined myself to spend time on the "entire home folder" problem as it almost certainly involves restricted stuff in the user's Library folder, which I don't think is of interest to test123testa anyway.

No further feedback from the OP as yet, but I've updated my script this morning to save a text file to the desktop like yours does.


NG

Offline

 

#14 2021-12-24 09:24:40 am

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 1369

Re: How do i iterate through every file including folders?

Nigel. I was studying your script to better understand its operation, and I changed code lines 1 and 2 below to code lines 3 and 4 below. I then removed the repeat loop that zapped any paths or files that begin with a ".". Afterwards, the script ran successfully on my home folder, which wasn't the case before, although its execution time with my standard test folder increased from 320 to 434 milliseconds (with the write file code disabled). Anyways, a user who has a compelling need to get the visible contents of their home folder might consider this option.

Applescript:

-- existing code
set subfolderPaths to path of thisFolder's folders
set fileNames to name of thisFolder's files

-- new code
set subfolderPaths to path of every folder of thisFolder whose visible is true
set fileNames to name of every file of thisFolder whose visible is true


2018 Mac mini - macOS Monterey - Script Debugger 8

Offline

 

#15 2021-12-24 02:31:31 pm

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 5530

Re: How do i iterate through every file including folders?

Thanks, peavine. I'm afraid the 'whose' filters are giving me timeout errors on large folders — not necessarily in my Library folder. I'll look into it further at more leisure. Perhaps not this evening.  smile

Happy Christmas!


NG

Offline

 

#16 2021-12-24 02:41:08 pm

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 1369

Re: How do i iterate through every file including folders?

Thanks Nigel, and a Happy Christmas to you as well.


2018 Mac mini - macOS Monterey - Script Debugger 8

Offline

 

#17 2021-12-27 04:29:21 pm

Nigel Garvey
Moderator
From:: Warwickshire, England
Registered: 2002-11-20
Posts: 5530

Re: How do i iterate through every file including folders?

Hi peavine.

It turns out that my System Events script can (often!) negotiate my own home folder without needing to check the disk items' 'visibility' properties. But a couple of my subfolder names run foul of a filing system bug — in Mojave, anyway. These folders were attached to an e-mail I received in 2005 and have names which told me where their contents had to go for the purpose being discussed at the time:  eg. "put into ~/Library/Contextual Menu Items/". The HFS paths to these folders should end with either the trailing slash or with both the trailing slash and a colon. But the 'path' returned by System Events only has a colon at the end, so it's incorrect and can't be used to identify the folders. This appears to be a file system fault rather than a System Events one, as a similar thing occurs with AppleScript's own files and aliases:

Applescript:

"iMac HD:blah:blah:put into ~/Library/Contextual Menu Items/:" as «class furl»
result as text
--> "iMac HD:blah:blah:put into ~/Library/Contextual Menu Items:" -- (Trailing slash omitted.)

System Events does have its own quirk though. If it's used to get just the folders' names instead of their full paths, all the slashes in the names are replaced with colons! It apparently gets what might be called the "POSIX names".

An unlikely workaround in the case of the paths is to use System Events to get the folders' 'POSIX paths' (which it gets right), sort on those, and then get the HFS 'paths' from folder objects specified using the POSIX paths!

Applescript:

tell application "System Events"
   set thisFolder to folder folderHFSPath
   set subfolderPOSIXPaths to POSIX path of thisFolder's folders
   -- [snip]
end tell

-- [snip]

repeat with thisPOSIXPath in subfolderPOSIXPaths
   set thisPOSIXPath to thisPOSIXPath's contents
   tell application "System Events" to set subfolderHFSPath to path of folder thisPOSIXPath
   recurse(subfolderHFSPath)
end repeat

I've modified the script in post #9 accordingly, but it's probably overkill for the OP's purposes.


NG

Offline

 

#18 2021-12-27 07:12:59 pm

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 1369

Re: How do i iterate through every file including folders?

Nigel. I tested your revised script on a documents folder and my home folder, and it worked great in both instances. The workaround is an interesting one. I agree these scripts will probably be of no use to the OP, but I suspect other forum members and googlers will find these scripts to be helpful in the future.


2018 Mac mini - macOS Monterey - Script Debugger 8

Offline

 

#19 2022-06-15 03:45:15 pm

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 1369

Re: How do i iterate through every file including folders?

I had posted a script here, but it did not sort correctly. I have revised my script in post 4, and it works as expected.

Last edited by peavine (2022-06-20 08:37:35 am)


2018 Mac mini - macOS Monterey - Script Debugger 8

Offline

 

#20 2022-06-15 04:38:50 pm

robertfern
Member
Registered: 2011-11-29
Posts: 150

Re: How do i iterate through every file including folders?

I always use "System Events" over Finder.
I find it to be more reliable.

Try this routine on your large folder and see if it craps out.

Applescript:


set folderTree to getFolderTree()

on getFolderTree()
   local theFolders
   set theFolder to (choose folder)
   set folderTree to {theFolder as text}
   
   tell application "System Events"
       set theFiles to (name of every file in theFolder)
       if theFiles ≠ {} then set the end of folderTree to theFiles
       
       try
           set theFolders to (every folder of the theFolder) as list
       on error
           display alert "No folders were found in the selected folder"
           error number -128
       end try
       
       repeat with aFolder in theFolders
           set contents of aFolder to path of aFolder
       end repeat
       --set theFolders to sortFolders(theFolders) of me -- disable to change folder sort
       sortFolders(theFolders) of me
       --=theFolders
       repeat with aFolder in theFolders
           set end of folderTree to linefeed & aFolder
           set theFiles to name of every file in folder aFolder
           if theFiles ≠ {} then set the end of folderTree to theFiles
       end repeat
   end tell
   
   set {ATID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, linefeed}
   set folderTree to folderTree as text
   set AppleScript's text item delimiters to ATID
   return folderTree
end getFolderTree

on sortFolders(a)
   repeat with i from (count a) to 2 by -1
       repeat with j from 1 to i - 1
           if item j of a > item (j + 1) of a then
               set {item j of a, item (j + 1) of a} to {item (j + 1) of a, item j of a}
           end if
       end repeat
   end repeat
   --return a (Not needed since routine sorts the list in-place which was passed by reference by default)
end sortFolders

Last edited by robertfern (2022-06-15 04:58:38 pm)

Offline

 

#21 2022-06-15 05:16:55 pm

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 1369

Re: How do i iterate through every file including folders?

robertfern wrote:

I always use "System Events" over Finder.
I find it to be more reliable.

Try this routine on your large folder and see if it craps out.



It only returned folder/files one level deep, and it returned hidden files (mainly .DS_Store).


2018 Mac mini - macOS Monterey - Script Debugger 8

Offline

 

#22 2022-06-15 08:14:23 pm

robertfern
Member
Registered: 2011-11-29
Posts: 150

Re: How do i iterate through every file including folders?

Here is a recursive version (much neater)

Try this one

Applescript:


on run
   local theFolder
   set theFolder to (choose folder) as text
   set folderTree to getFolderTree(theFolder)
end run

on getFolderTree(theFolder)
   local theFolders, folderTree, theFiles
   set folderTree to (theFolder as text) & linefeed
   set {ATID, text item delimiters} to {text item delimiters, linefeed}
   tell application "System Events"
       set theFiles to (name of every file in folder theFolder whose visible is true)
       sortFolders(theFiles) of me
       if theFiles ≠ {} then set folderTree to folderTree & theFiles as text
       try
           set theFolders to (path of every folder of folder theFolder) --as list
       on error
           tell me to display alert "No folders were found in the selected folder"
           error number -128
       end try
   end tell
   set folderTree to folderTree & linefeed & linefeed
   sortFolders(theFolders)
   repeat with aFolder in theFolders
       set folderTree to folderTree & getFolderTree(contents of aFolder)
   end repeat
   set text item delimiters to ATID
   return folderTree
end getFolderTree

on sortFolders(a)
   repeat with i from (count a) to 2 by -1
       repeat with j from 1 to i - 1
           if item j of a > item (j + 1) of a then
               set {item j of a, item (j + 1) of a} to {item (j + 1) of a, item j of a}
           end if
       end repeat
   end repeat
end sortFolders

Last edited by robertfern (2022-06-15 08:17:34 pm)

Offline

 

#23 2022-06-16 06:52:18 am

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 1369

Re: How do i iterate through every file including folders?

robertfern wrote:

Here is a recursive version (much neater)

Try this one



I tested the script on my test folder and it worked fine. The timing result was 320 milliseconds.


2018 Mac mini - macOS Monterey - Script Debugger 8

Offline

 

#24 2022-06-16 10:00:19 am

robertfern
Member
Registered: 2011-11-29
Posts: 150

Re: How do i iterate through every file including folders?

I was trying my script above with a folder that had over 9000 files.
It took forever and I had to increase the timeout value so that System Events would return the file list.
It seems that the "whose" clause really slows down the result.
If I remove the whose clause, it responded almost instantaneously.
So I decided to parse the list using AppleScript to remove invisible files from the result.
It is much faster!

Also the sort routine was extremely slow, so I replaced it with a combSort which is way faster than the bubble sort that was used before.

Applescript:


on run
    local theFolder
    set theFolder to (choose folder) as text
    set folderTree to getFolderTree(theFolder)
    saveFolderTree(folderTree)
end run

on getFolderTree(theFolder)
   local theFolders, folderTree, theFiles, visList
   set folderTree to (theFolder as text) & linefeed
   set {ATID, text item delimiters} to {text item delimiters, linefeed}
   try
       tell application "System Events"
           set {theFiles, visList} to {name, visible} of files in folder theFolder --whose visible is true
       end tell
   on error
       return ""
   end try
   repeat with i from (count of theFiles) to 1 by -1
       if item i of visList is false then
           set item i of theFiles to item 1 of theFiles
           set item i of visList to item 1 of visList
           set theFiles to rest of theFiles
           set visList to rest of visList
       end if
   end repeat
   set visList to missing value
   combSort(theFiles)
   if theFiles ≠ {} then set folderTree to folderTree & theFiles as text
   try
       tell application "System Events"
           set {theFolders, visList} to {path, visible} of folders of folder theFolder
       end tell
   on error
       tell me to display alert "No folders were found in the selected folder"
       error number -128
   end try
   repeat with i from (count of theFolders) to 1 by -1
       if item i of visList is false then
           set item i of theFolders to item 1 of theFolders
           set item i of visList to item 1 of visList
           set theFolders to rest of theFolders
           set visList to rest of visList
       end if
   end repeat
   set folderTree to folderTree & linefeed & linefeed
   combSort(theFolders)
   repeat with aFolder in theFolders
       set folderTree to folderTree & getFolderTree(contents of aFolder)
   end repeat
   set text item delimiters to ATID
   return folderTree
end getFolderTree

on saveFolderTree(theText)
   set theFile to (path to desktop as text) & "Folder Contents.txt"
   try
       set fnum to open for access file theFile with write permission
   on error
       display alert "Oops!"
       return
   end try
   set eof fnum to 0
   write theText to fnum starting at 0
   close access fnum
end saveFolderTree

on combSort(alist as list) -- FASTEST
   local i, j, cc, sf, ns, js, gap, pgap, sw -- ns means No Swap
   script mL
       property nlist : alist
   end script
   set sf to 1.5
   set cc to count mL's nlist
   set gap to cc div sf
   repeat until gap = 0
       repeat with i from 1 to gap
           set js to cc - gap
           repeat until js < 1 -- do each gap till nor more swaps
               set ns to gap
               repeat with j from i to js by gap
                   if (item j of mL's nlist) > (item (j + gap) of mL's nlist) then
                       set sw to (item j of mL's nlist)
                       set (item j of mL's nlist) to (item (j + gap) of mL's nlist)
                       set (item (j + gap) of mL's nlist) to sw
                       set ns to j
                   end if
               end repeat
               set js to ns - gap
           end repeat
       end repeat
       set pgap to gap
       set gap to gap div sf
       if gap = 0 then -- no while using as integer
           if pgap ≠ 1 then set gap to 1
       end if
   end repeat
end combSort

Last edited by robertfern (2022-06-19 09:14:59 am)

Offline

 

#25 2022-06-19 10:01:03 am

estockly
Member
Registered: 2009-01-03
Posts: 51

Re: How do i iterate through every file including folders?

If you don't mind using script libraries, this can be done with Shane's fileManagerLib.

https://latenightsw.com/freeware/

Applescript:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
use framework "Foundation"

use script "FileManagerLib" version "2.3.5"
on main()
   set theFolder to POSIX path of (choose folder)
   
   set filesFolders to objects of theFolder ¬
       searching subfolders true ¬
       include invisible items false ¬
       include folders true ¬
       include files true ¬
       result type files list
   set AppleScript's text item delimiters to {return}
   set theText to filesFolders as text
   saveFolderTree(theText)
end main

on saveFolderTree(theText)
   set theFile to (current application's NSHomeDirectory()'s stringByAppendingPathComponent:"Desktop")'s stringByAppendingPathComponent:"Folder Contents.txt"
   (current application's NSString's stringWithString:theText)'s writeToFile:theFile atomically:true encoding:(current application's NSUTF8StringEncoding) |error|:(missing value)
end saveFolderTree

main()

Last edited by estockly (2022-06-19 10:02:19 am)

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)