使用 NSSavePanel 将文件从 Bundle 保存/复制到桌面

Posted

技术标签:

【中文标题】使用 NSSavePanel 将文件从 Bundle 保存/复制到桌面【英文标题】:Save/Copy a file from Bundle to Desktop using NSSavePanel 【发布时间】:2016-12-17 10:46:57 【问题描述】:

我正在创建一个 macOS 应用程序,该应用程序在其 Bundle 目录中附带一些 .zip 文件。

用户应该能够将这些文件从我的应用程序保存到自定义目录。

我找到了NSSavePanel,并认为这是正确的方法——这就是我目前所拥有的:

@IBAction func buttonSaveFiles(_ sender: Any) 

    let savePanel = NSSavePanel()

    let bundleFile = Bundle.main.resourcePath!.appending("/MyCustom.zip")

    let targetPath = NSHomeDirectory()
    savePanel.directoryURL = URL(fileURLWithPath: targetPath.appending("/Desktop")) 
    // Is appeding 'Desktop' a good solution in terms of localisation?

    savePanel.message = "My custom message."
    savePanel.nameFieldStringValue = "MyFile"
    savePanel.showsHiddenFiles = false
    savePanel.showsTagField = false
    savePanel.canCreateDirectories = true
    savePanel.allowsOtherFileTypes = false
    savePanel.isExtensionHidden = true

    savePanel.beginSheetModal(for: self.view.window!, completionHandler: _ in )


我不知道如何将bundleFile“移交”给savePanel

所以我的主要问题是:如何将文件从应用程序包保存/复制到自定义目录?

其他问题取决于NSSavePanel: 1) 好像默认没有本地化(我的Xcode方案设置为德语,但面板显示为英文),我必须自己自定义吗? 2) 有没有办法让面板默认展开?

【问题讨论】:

搜索 bundle 或 NSBundle 会有所帮助。 @ElTomato 我已经使用Bundle 来查找bundleFile 的路径(参见我上面的代码)。它对我描述的问题没有帮助。 哦,对不起……让我想想,我会回来找你的。 我会像 Eric 所说的那样使用 runModal。 【参考方案1】:

您应该使用Bundle.main.url 获取您现有的文件 URL,然后使用面板获取目标 URL,然后复制文件。该面板不对文件做任何事情,它只是获取它们的 URL。

例子:

// the panel is automatically displayed in the user's language if your project is localized
let savePanel = NSSavePanel()

let bundleFile = Bundle.main.url(forResource: "MyCustom", withExtension: "zip")!

// this is a preferred method to get the desktop URL
savePanel.directoryURL = FileManager.default.urls(for: .desktopDirectory, in: .userDomainMask).first!

savePanel.message = "My custom message."
savePanel.nameFieldStringValue = "MyFile"
savePanel.showsHiddenFiles = false
savePanel.showsTagField = false
savePanel.canCreateDirectories = true
savePanel.allowsOtherFileTypes = false
savePanel.isExtensionHidden = true

if let url = savePanel.url, savePanel.runModal() == NSFileHandlingPanelOKButton 
    print("Now copying", bundleFile.path, "to", url.path)
    // Do the actual copy:
    do 
        try FileManager().copyItem(at: bundleFile, to: url)
     catch 
        print(error.localizedDescription)
    
 else 
    print("canceled")

另外,请注意,是否展开面板是用户选择的,您不能从您的应用程序中强制它。

【讨论】:

非常感谢!很好的解决方案,工作正常。您是否也知道为什么 NSSavePanel 没有被翻译/本地化?我认为所有系统提供的 UI 元素都应该自动以相关语言显示。 不客气。面板将自动使用用户的语言 if your project is localized。从列表中添加新语言就足够了,如果您不想,则无需实际实施本地化 - 但您至少必须在此列表中添加语言,因为面板将需要它们。 Proper link for the Xcode screenshot 用于添加本地化。

以上是关于使用 NSSavePanel 将文件从 Bundle 保存/复制到桌面的主要内容,如果未能解决你的问题,请参考以下文章

XCTestCase 保存文件? (记录 NSSavePanel)?

基于 NSDocument 的应用程序:在 NSSavePanel 中选择默认文件类型

沙盒环境下关闭 NSSavePanel

将文件从应用程序包复制并保存到桌面/其他地方

更正权利标志以将文件保存在同一位置两次

如何从 Web 应用程序使用 OSGi 服务?