在Yosemite上使用JavaScript for Automation列出文件夹中的所有文件

Listing all the files in a folder using JavaScript for Automation on Yosemite

本文关键字:文件夹 文件 Automation Yosemite for JavaScript      更新时间:2023-09-26

我正在尝试将一些旧的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)
-- > []

我也试过很多其他的组合,但运气不好。有什么想法吗?

就像之前的Leopard脚本桥一样,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)原型,供JXA开发人员参考(他们很快就忽略了它,natch):

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

(虽然还没有完全完成或测试,但JOSA仍然比JXA工作得更好,有更好的文档记录,甚至包括一个用于将AS命令转换为JS语法的自动翻译工具。不幸的是,由于苹果已经将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对范围、过滤器、相对和插入引用表单的支持;它特别糟糕。)

"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)
    );
});

我可以像这样得到

 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命令处理任何事情,只能"打开"