Friday, January 28, 2022

#1 2021-08-09 08:06:31 pm

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

Get files and folders as shown in a Finder window

I wrote the following script which gets and sorts all files and folders in a folder in the exact order they are shown in a Finder window. The Finder window is set to sort by name in ascending order with folders displayed first and hidden files not shown. The following works but I wondered if there might be a simpler and faster ASObjC approach. I wrote this primarily to refine my ASObjC skills. Thanks.

Applescript:

use framework "Foundation"
use scripting additions

set theFolder to POSIX path of (choose folder)

getFinderList(theFolder)

on getFinderList(theFolder)
   set theFolder to current application's |NSURL|'s fileURLWithPath:theFolder
   
   set fileManager to current application's NSFileManager's defaultManager()
   set theOptions to (current application's NSDirectoryEnumerationSkipsPackageDescendants as integer) + (current application's NSDirectoryEnumerationSkipsHiddenFiles as integer)
   set enumKeys to {current application's NSURLIsDirectoryKey, current application's NSURLIsPackageKey}
   set theFiles to fileManager's contentsOfDirectoryAtURL:theFolder includingPropertiesForKeys:enumKeys options:theOptions |error|:(missing value)
   set theDescriptor to current application's NSSortDescriptor's sortDescriptorWithKey:"lastPathComponent" ascending:true selector:"localizedStandardCompare:"
   set sortedFiles to (theFiles's sortedArrayUsingDescriptors:{theDescriptor})
   
   set theFolders to current application's NSMutableArray's new()
   set theFiles to current application's NSMutableArray's new()
   repeat with anItem in sortedFiles
       set {theResult, isDirectory} to (anItem's getResourceValue:(reference) forKey:(current application's NSURLIsDirectoryKey) |error|:(missing value))
       if isDirectory as boolean then
           set {theResult, isPackage} to (anItem's getResourceValue:(reference) forKey:(current application's NSURLIsPackageKey) |error|:(missing value))
           if isPackage as boolean then
               (theFiles's addObject:anItem)
           else
               (theFolders's addObject:anItem)
           end if
       else
           (theFiles's addObject:anItem)
       end if
   end repeat
   
   set finderItemList to theFolders's arrayByAddingObjectsFromArray:theFiles
   return finderItemList as list
end getFinderList


2018 Mac mini - macOS Monterey - Script Debugger 8

Offline

 

#2 2021-08-10 09:28:32 am

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

Re: Get files and folders as shown in a Finder window

Hi peavine.

If you know you have significantly fewer folders than files in the folder, or vice versa, a v-e-r-y slightly more efficient approach would be only to build an array of the fewer items and then "subtract" it from the full one. This may even be effective with a more even mix.

Applescript:

use framework "Foundation"
use scripting additions

set theFolder to POSIX path of (choose folder)

getFinderList(theFolder)

on getFinderList(theFolder)
   set theFolder to current application's |NSURL|'s fileURLWithPath:theFolder
   
   set fileManager to current application's NSFileManager's defaultManager()
   set theOptions to (current application's NSDirectoryEnumerationSkipsPackageDescendants as integer) + (current application's NSDirectoryEnumerationSkipsHiddenFiles as integer)
   set enumKeys to {current application's NSURLIsDirectoryKey, current application's NSURLIsPackageKey}
   set theFiles to (fileManager's contentsOfDirectoryAtURL:theFolder includingPropertiesForKeys:enumKeys options:theOptions |error|:(missing value))
   
   set theFiles to theFiles's mutableCopy()
   set theDescriptor to current application's NSSortDescriptor's sortDescriptorWithKey:"lastPathComponent" ascending:true selector:"localizedStandardCompare:"
   theFiles's sortUsingDescriptors:{theDescriptor}
   
   set arrangedItems to current application's NSMutableArray's new() -- Formerly theFolders.
   repeat with anItem in theFiles
       set {theResult, isDirectory} to (anItem's getResourceValue:(reference) forKey:(current application's NSURLIsDirectoryKey) |error|:(missing value))
       if isDirectory as boolean then
           set {theResult, isPackage} to (anItem's getResourceValue:(reference) forKey:(current application's NSURLIsPackageKey) |error|:(missing value))
           if not (isPackage as boolean) then (arrangedItems's addObject:anItem)
       end if
   end repeat
   
   theFiles's removeObjectsInArray:arrangedItems
   arrangedItems's addObjectsFromArray:theFiles
   
   return arrangedItems as list
end getFinderList


NG

Offline

 

#3 2021-08-10 02:13:22 pm

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

Re: Get files and folders as shown in a Finder window

Thanks Nigel. Your suggestion works great but I had to put it to the test smile

TEST FOLDER CONTAINS - PEAVINE'S SCRIPT - NIGEL'S SCRIPT

8 folders 8 files - 41 - 37 (all times are milliseconds)
4 folders 16 files - 38 - 32
2 folders 57 files - 83 - 61

To set a baseline, I tested a Finder script which returns the same results (except as aliases) on the third test folder above and the timing result was 288 milliseconds.

Last edited by peavine (2021-08-10 06:58:43 pm)


2018 Mac mini - macOS Monterey - Script Debugger 8

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)