Kann AppleScript gründlich nach der größten Datei suchen, die sich unterhalb eines Ordners befindet?

Ich muss ein AppleScript erstellen, das die größte Datei im ausgewählten Verzeichnis findet (auch wenn sie sich in einem anderen Ordner befindet) und den vollständigen Pfad auf dem Bildschirm anzeigt.

Folgendes habe ich bisher, aber es funktioniert nicht:

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

Ich bin mir nicht sicher, wie ich anhand des obigen Skripts feststellen soll, was nicht funktioniert. Können Sie beim nächsten Schritt helfen, damit dies funktioniert?

Antworten (2)

Es gibt verschiedene Methoden, um diese Aufgabe zu erfüllen, jede mit Vor- und Nachteilen. Die Shell-Methoden sind schnell , geben aber nicht immer aktuelle Informationen zurück . Die Finder- Oberfläche von AppleScript ist nicht so langsam, wie ich dachte, sondern gibt nur brauchbare Werte für Dateigrößen zurück, die zwischengespeichert wurden, andernfalls "fehlender Wert" für den Rest. Systemereignisse ist normalerweise die AppleScript-Dateiverwaltungsanwendung der Wahl, da es beim Abrufen schnell ist, aber beim Zugriff auf Dateiattribute langsamer wird. Es kann auch keine tiefe Verzeichnisaufzählung durchführen, wie es der Finder kann (obwohl eine manuell implementiert werden kann).

Ich habe mich entschieden, die Objective-C-Scripting-Bridge zu verwenden, um ein AppleScript zu schreiben, das sowohl superschnell ist als auch in der Lage ist, in die Unterordner eines Verzeichnisses abzusteigen. Insgesamt ist es die beste Methode, hat aber den Nachteil, dass dein Lehrer etwas misstrauisch sein könnte.

# 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:

Dies wird als Alternative zu dem in der anderen Antwort verwendeten AppleScript Objective-C- Code angeboten und entspricht eher dem im OP gezeigten Standard - AppleScript- Code . Beachten Sie, dass diese Antwort dem Autor der anderen Antwort, CJK, zu verdanken ist, da sie aus jetzt gelöschten Kommentaren stammt, die wir uns unter seiner ursprünglichen Antwort gegenseitig gemacht haben. Außerdem halte ich seine Antwort trotz der Komplexität für leistungsmäßig überlegen gegenüber dem, was hier angeboten wird.

Wenn dieses Skript ausgeführt wird, wählt der Benutzer einen Ordner aus und das Endergebnis, der größte Dateipfadname innerhalb des ausgewählten Ordners, einschließlich seiner Unterordner, wird in einem Dialogfeld angezeigt.

Beispiel AppleScript -Code :

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.

Das Endergebnis in meinem Downloads-Ordner ist das unten gezeigte Dialogfeld:

Dialogfeld anzeigen

Der angezeigte Pfaddateiname ist derzeit mit 5,27 GB auf der Festplatte die größte Datei in meinem Downloads-Ordner.


Hinweis: Der Beispiel -AppleScript- Code ist genau das und enthält keine Fehlerbehandlung, wie es angebracht sein könnte. Es obliegt dem Benutzer, eine Fehlerbehandlung hinzuzufügen, die angemessen, erforderlich oder gewünscht ist.

@CJK, ich habe diese Antwort teilweise basierend auf den jetzt gelöschten Kommentaren aus Ihrer Antwort hinzugefügt.
Und ich denke, es verdient eine +1.