AppleScript può cercare in profondità il file più grande contenuto sotto una cartella?

1

Ho bisogno di creare un AppleScript che trovi il file più grande nella directory selezionata (anche se è all'interno di un'altra cartella) e mostra il percorso completo sullo schermo.

Questo è quello che ho finora, ma non funziona:

set theItem to quoted form of POSIX path of (choose folder)

set theSize to (do shell script "/usr/bin/mdls -name kMDItemFSSize -raw " & theItem)

on open f

set filePath to do shell script "dirname " & POSIX path of f as string

display dialog theFilePath

Non sono sicuro di come dire cosa non funziona dallo script sopra. Puoi aiutarmi con il prossimo passo nel fare questo lavoro?

    
posta Ignas Cibulskas 11.12.2018 - 22:25
fonte

2 risposte

2

Esistono vari metodi per svolgere questa attività, ciascuno con pro e contro. I metodi di shell sono veloci- ish , ma non sempre restituiscono informazioni aggiornate . L'interfaccia Finder di AppleScript non è così lenta come pensavo, ma restituisce solo valori validi per le dimensioni dei file che sono state memorizzate nella cache, altrimenti "valore mancante" per il resto. Eventi di sistema normalmente è il file AppleScript che gestisce l'applicazione preferita, poiché è veloce al momento del recupero, ma rallenta quando si accede agli attributi dei file. Inoltre, non può eseguire un'enumerazione di directory profonda come Finder (anche se può essere implementata manualmente).

Ho deciso di utilizzare il bridge di scripting Objective-C per scrivere un AppleScript che sia super veloce e pienamente capace di discendere nelle sottocartelle di una directory. Nel complesso, è il metodo migliore, ma presenta l'inconveniente che il tuo insegnante potrebbe essere un po 'sospettoso.

# Loads the Foundation framework into the script so that we can access its
# methods and constants
use framework "Foundation"

# Declare properties that belong to the Foundation framework for easier
# referencing within the script
property this : a reference to current application
property NSArray : a reference to NSArray of this
property NSDirectoryEnumerationSkipsHiddenFiles : a reference to 4
property NSDirectoryEnumerationSkipsPackageDescendants : a reference to 2
property NSFileManager : a reference to NSFileManager of this
property NSSortDescriptor : a reference to NSSortDescriptor of this
property NSString : a reference to NSString of this
property NSURL : a reference to NSURL of this
property NSURLFileSizeKey : a reference to NSURLFileSizeKey of this
property NSURLNameKey : a reference to NSURLNameKey of this
property NSURLPathKey : a reference to NSURLPathKey of this

# Call the handler defined below.  This is where the script does the actual
# retrieving of the files and filesizes
get my contentsOfDirectory:"~/Downloads"

# If we stopped the script at the line above, you'd see the entire contents of 
# the directory subtree listed with file paths and filesizes, ordered in 
# descending order by filesize.  However, you only want the largest file, so
# we pick out the first item in the list.
return item 1 of the result

--------------------------------------------------------------------------------
# This is an AppleScript handler declaration
on contentsOfDirectory:dir
    local dir # This tells the handler that the variable passed as the
    # parameter is limited in scope to this handler

    # Obtain a reference to the default file manager of the filesystem
    set FileManager to NSFileManager's defaultManager()

    # This is where retrieve the contents of the directory, recursing
    # into any subfolders.  The options declared tell the method to skip
    # hidden files and not to look inside file packages, such as 
    # applications or library files.  I've declared a list of keys that
    # pre-fetch file attributes during this retrieval, making it faster
    # to access their data later: filename, full path, and file size.
    set fs to FileManager's enumeratorAtURL:(NSURL's ¬
        fileURLWithPath:((NSString's stringWithString:dir)'s ¬
            stringByStandardizingPath())) ¬
        includingPropertiesForKeys:[¬
        NSURLPathKey, ¬
        NSURLNameKey, ¬
        NSURLFileSizeKey] ¬
        options:(NSDirectoryEnumerationSkipsHiddenFiles + ¬
        NSDirectoryEnumerationSkipsPackageDescendants) ¬
        errorHandler:(missing value)

    # I created the script object just to speed up the process of
    # appending new items to the empty list it contains.
    script |files|
        property list : {}
    end script

    # This is the repeat loop that we use to enumerate the contents
    # of the directory tree that we retrieved above
    repeat
        # This allows us to access each item in the enumerator one
        # by one.
        set f to fs's nextObject()

        # Once the list has been exhausted, the value returned above
        # will be a "missing value", signifying that there are no more
        # files to enumerate.  Therefore, we can exit the loop.
        if f = missing value then exit repeat

        # Here, we retrieve the values of file attributes denoted
        # by the keys I declared earlier.  I'm picking out the path
        # and the filesize as per your needs.
        f's resourceValuesForKeys:[NSURLPathKey, NSURLFileSizeKey] ¬
            |error|:(missing value)

        # The above command returns a record containing the two
        # file attributes.  This record gets appended to the list
        # stored in the script object above.
        set end of list of |files| to the result as record
    end repeat

    # The list in the script object is an AppleScript list object.  For
    # the next part, I need a cocoa list object (NSArray).
    set L to item 1 of (NSArray's arrayWithObject:(list of |files|))

    # This defines a sort descriptor which is used to sort the array.
    # I'm telling it to use the filesize key to sort the array by 
    # filesize, which will let us grab the largest file easily.
    set descriptor to NSSortDescriptor's alloc()'s ¬
        initWithKey:"NSURLFileSizeKey" ascending:no

    # Sort the list.
    L's sortedArrayUsingDescriptors:[descriptor]

    # Return the result.
    result as list
end contentsOfDirectory:
    
risposta data 12.12.2018 - 05:29
fonte
1

Questo viene offerto come alternativa al codice ObjectScript-C utilizzato nell'altra risposta ed è più simile allo standard em> codice AppleScript mostrato nell'OP. Nota che il credito per questa risposta va all'autore dell'altra risposta, CJK, poiché deriva dai commenti ora cancellati che abbiamo fatto l'un l'altro sotto la sua risposta originale. Inoltre, considero la sua risposta, nonostante la complessità, essere superiore nelle prestazioni a ciò che viene offerto qui.

Quando viene eseguito questo script, l'utente sceglie una cartella e il risultato finale, il percorso più grande dei file all'interno della cartella scelta, incluse le sue sottocartelle, viene visualizzato in una finestra di dialogo.

Esempio AppleScript codice :

set chosenFolder to quoted form of POSIX path of ¬
    (text items 1 thru -2 of ((choose folder) as text) as text)

set theLargestFilePathname to ¬
    (do shell script "find " & chosenFolder & ¬
        " -type f -ls | sort -nrk7 | awk '{for(i=11; i<=NF; ++i) printf $i\"\"FS; exit}'")

display dialog "The largest file within the chosen folder, and its subfolders, is:" & ¬
    linefeed & linefeed & theLargestFilePathname buttons {"OK"} default button 1 ¬
    -- giving up after 3        # Remove the '--' at the front of this line to enable this.

Il risultato finale nella mia cartella Download è la finestra di dialogo mostrata di seguito:

Il nome file del percorso mostrato è, al momento, il file più grande nella mia cartella Download a 5,27 GB su disco.

Nota: il esempio codice AppleScript è proprio questo e non contiene alcuna gestione degli errori che potrebbe essere appropriata. L'onere spetta all'utente di aggiungere qualsiasi gestione degli errori che potrebbe essere appropriata, necessaria o desiderata.

    
risposta data 13.12.2018 - 02:42
fonte

Leggi altre domande sui tag