【问题标题】:Listing all the files in a folder using JavaScript for Automation on Yosemite使用 JavaScript for Automation on Yosemite 列出文件夹中的所有文件
【发布时间】:2014-12-05 18:09:41
【问题描述】:

我正在尝试将一些旧的 Applescript 移植到新的 JavaScript 语法中。

有些事情似乎很简单,所以:

tell application "System Events" to keystroke "t" using command down

变成:

System = Application('System Events');
System.keystroke("t", {using: "command down"})

但是,我终其一生都无法弄清楚如何在特定位置列出文件。在 AppleScript 中,要返回 /usr 目录中的文件列表,您可以:

tell application "System Events" to set fileList to name of items in folder "/usr"
-- > {"bin", "include", "lib", "libexec", "local", "sbin", "share", "standalone", "X11"}

但是,我终其一生都无法弄清楚如何用 Javascript 来实现。

System = Application('System Events')
myPath = Path("/usr")

fileList = System.items(myPath) 
-- > message not understood

fileList = System.folder(myPath)
-- > message not understood

fileList = System.diskItems(myPath)
-- > []

fileList = System.diskItems({at:myPath)
-- > []

我也尝试了很多其他组合,但没有运气。有什么想法吗?

【问题讨论】:

    标签: javascript automation applescript osx-yosemite javascript-automation


    【解决方案1】:

    "System Events" 方法确实具有简单的优点,但事实证明,使用 $.NSFileManager(现在可直接用于脚本编写)可以显着提高性能。

    在我的系统上,开始比较

    var strPath = '/usr';
    
    var appSys = Application('System Events'),
    lstHarvest = appSys.folders.byName(strPath).diskItems.name();
    

    几千次迭代的快速测试表明,我们可以通过这种略显巴洛克式的方法将其始终加快 40%:

    var strPath = '/usr';
    var fm = $.NSFileManager.defaultManager,
        oURL = $.NSURL.fileURLWithPathIsDirectory(strPath, true),
        lstFiles = ObjC.unwrap(
            fm.contentsOfDirectoryAtURLIncludingPropertiesForKeysOptionsError(
                oURL, [], 1 << 2, null
            )
        ),
        lstHarvest = [];
    
    lstFiles.forEach(function (oItem) {
        lstHarvest.push(
            ObjC.unwrap(oItem.path)
        );
    });
    

    使用更简单的方法可以提高 300% 以上:

    var strPath = '/usr';
    var fm = $.NSFileManager.defaultManager,
        lstFiles = ObjC.unwrap(
            fm.contentsOfDirectoryAtPathError(strPath, null)
        ),
        lstHarvest = [];
    
    lstFiles.forEach(function (oItem) {
        lstHarvest.push(
            ObjC.unwrap(oItem)
        );
    });
    

    【讨论】:

      【解决方案2】:

      就像之前的Leopard's Scripting Bridge 一样,JXA 故意破坏了各种在 AppleScript 中完美运行的东西。以下是将原始 AppleScript 命令翻译成 JXA 语法:

      //tell application "System Events" to name of items in folder "/usr"
      Application('System Events').folders.byName('/usr').items.name()
      

      AS 版本完美运行,但 JXA 等效版本只是抛出一个完全没有意义的Error -1700: Can't convert types.

      如果你写 diskItems 而不是 items,JXA 似乎确实有效:

      Application('System Events').folders.byName('/usr').diskItems.name()
      // --> ["bin", "lib", "libexec", "local", "sbin", "share", "standalone", "X11", "X11R6"]
      

      这表明 JXA 沉迷于导致 SB 在许多应用程序上崩溃的相同内部“聪明”。 (请注意,我在早期的测试中发现了许多此类设计缺陷,但一旦明确 AS 开发人员只关心将自己的个人意识形态和偏见强加给其他人,我就放弃了报告它们,该死的能力和兼容性受损。)

      作为比较,这是几个月前我快速整理的 JavaScriptOSA (JOSA) prototype 供 JXA 开发人员参考(他们很快就忽略了它,natch):

      app('System Events').folders.named('/usr').items.name()
      // -> ["bin", "lib", "libexec", "local", "sbin", "share", "standalone", "X11", "X11R6"]
      

      (虽然还没有完全完成或测试,但 JOSA 仍然比 JXA 工作得更好,文档更好,甚至包括一个自动翻译工具,用于将 AS 命令转换为 JS 语法。不幸的是,因为 Apple 已经遗留或弃用了AEM、CM、PM 和 OSA Carbon API,我不建议将其用于生产用途;它纯粹是为了比较。)

      同样:

      set myPath to POSIX file "/usr"
      tell application "System Events" to name of every disk item of folder named myPath
      --> {"bin", "lib", "libexec", "local", "sbin", "share", "standalone", "X11", "X11R6"}
      
      myPath = Path('/usr')
      Application('System Events').folders.byName(myPath).diskItems.name()
      // Error -1728: Can't get object.
      
      var myPath = Path('/usr')
      app('System Events').folders.named(myPath).diskItems.name()
      // --> ["bin", "lib", "libexec", "local", "sbin", "share", "standalone", "X11", "X11R6"]
      

      您可以通过将 Path 对象转换为字符串并使用它来解决这种特殊情况:

      myPath = Path('/usr')
      Application('System Events').folders.byName(myPath.toString()).diskItems.name()
      

      虽然这种解决方法在其他情况下不一定有帮助;例如它在 Finder 中失败,因为 Finder 不理解 POSIX 样式的路径字符串,并且无法从 JXA Path 对象获取 HFS 样式的路径字符串(Finder 确实可以理解):

      set myPath to POSIX file "/usr"
      tell application "Finder" to name of every item of item myPath
      --> {"X11", "X11R6", "bin", "lib", "libexec", "local", "sbin", "share", "standalone"}
      
      myPath = Path('/usr')
      Application('Finder').folders.byName(myPath.toString()).items.name()
      // Error -1728: Can't get object.
      

      就这样。 (例如,尝试测试 JXA 对范围、过滤器、相对和插入的支持 reference forms;它特别烂。)

      【讨论】:

      • 哇,答案非常全面。我想如果它使事情更容易理解(在这种情况下可以说是正确的)并且有体面,清晰的文档,那么进行更改(diskItems 的项目)不会有太多问题。情况似乎根本不是这样(至少现在还没有,它仍然是一个测试版——他满怀希望地说)。也就是说,如果您要进行这样的语义更改,那么肯定会像 Application('Finder').diskItems({atPath:path, return: "names", includeSubDirectories:true, excludeInvisibles:true ) 等更有意义,至少在我之上。
      • JXA 并没有做出改变以使事情更容易理解;它破坏了兼容性,因为它的开发人员不喜欢和/或不了解 Apple 事件 IPC 的工作原理。可编写脚本的应用程序[i]已经定义了所有的行为[/i]。作为这些应用程序的[i]客户端[/i],JXA 有责任全面和正确地支持这些行为,而不是仅仅因为它冒犯了 JXA 开发人员的个人信仰而大发雷霆。这是病态的后座驾驶,仅此而已。
      • 好的。那么有什么方法可以确定在任何给定时间实际应用的方法/属性。在这方面,文档没有太多帮助。我可以在文档 Application('System Events').folder 中找到,但没有引用 byName()。而且您似乎无法一次构建命令。 Application('System Events').folders.byName('/usr') 不返回任何内容,那么您怎么知道将 .diskItems.name() 应用于它?你只需要知道这些东西吗?或者你是怎么解决的?
      • 恐怕很多都是经验和有根据的猜测。这是 AppleScript 平台的几个众所周知的长期缺陷之一。唉,AS 团队更喜欢发明新问题,而不是解决已有的问题。众所周知,应用程序字典含糊不清且不完整,而且 Script Editor 的字典查看器并不是特别擅长呈现其中的信息。脚本调试器要好得多,尽管您需要为此付费。我建议你买一本关于 AppleScript 的好书;这不是几个 cmets 可以充分覆盖的东西。 ://
      • 很好的答案...但同样,您如何具体知道 Application('System Events').folders 或其函数 byName() 的存在,或者 byName() 返回的内容diskItems 属性等?这些特定于 JXA 的信息从何而来?
      【解决方案3】:

      我可以这样弄

       foldersList =  foldersList =  System.folders.byName("usr").folders.name()
      

      -> [“bin”、“lib”、“libexec”、“sbin”、“share”、“standalone”、“X11”]

      即使这样也有效:

         foldersList =  System.folders.byName("/Users/USERName/Documents/").folders.name()
      

      但到目前为止,除了“打开”之外,我无法让 Path 命令处理任何事情

      【讨论】:

        猜你喜欢
        • 2019-11-02
        • 2020-07-02
        • 1970-01-01
        • 2011-10-30
        • 2014-12-25
        • 2012-08-12
        • 2018-08-06
        • 2013-10-23
        • 1970-01-01
        相关资源
        最近更新 更多