为什么FileHandle不一致地返回'nil'

时间:2018-05-31 20:57:45

标签: swift macos-high-sierra

我有一个应用程序在使用FileHandle为Read打开文件时不一致地返回'nil'。我在OSX(10.13.4),XCode 9.4,Swift 4.1

此OSX应用程序使用NSOpenPanel()来获取用户选择的文件列表。我的“模型”类代码打开这些文件以构建数据结构的集合执行此操作的代码就像这样开始并成功获取任何文件的FileHandle并且能够从文件中读取数据。

private func getFITHeader(filename: String) {
    let file: FileHandle? = FileHandle(forReadingAtPath: filename)
    if file == nil {
        print("FITFile >>> File open failed for file \(filename)")
    }
    else {
        var databuffer: Data
        databuffer = (file?.readData(ofLength: 80))!
        :
        :
    }

这些文件还包含一个二进制数据块,我在应用程序的另一部分处理。当我为此开发代码时,我暂时硬编码与上述工作相同的文件名之一用于测试目的。但是这个代码(下面)总是抛出一个异常'线程1:致命错误:当它到达fileHandle时,意外地发现nil在展开一个可选值时出现了吗?.seek() - 由于某种原因尝试创建一个FileHandle始终返回'nil',尽管代码在功能上与上面相同。

@IBAction func btnProcFile(_ sender: Any) {

    var data: Data
    let filename = "/Users/johncneal/Dropbox/JN Astronomy/Astronomy/Spectroscopy/RSpec_Analyses/Gamma_Cas/20161203/Gamma Cas_065.fit"

    let fileHandle: FileHandle? = FileHandle(forReadingAtPath: filename)
    fileHandle?.seek(toFileOffset: 2880) //skip past the headers

    let dataLenToRead = 1391 * 1039 * 2
    data = (fileHandle?.readData(ofLength: dataLenToRead))!
    :
    :
}

第二个函数中的代码在Playground中工作正常(没有太多意义),而且,当临时添加到另一个项目时,它也可以工作。也许值得一提的是文件路径的长度似乎并不重要 - 它在短路径上的行为相同。

所以问题是 - 为什么FileHandle的这种行为可靠地不一致?

print()'提交给FileHandle()的文件名显示它们在每种情况下都是相同的(见下文)。所以我对此感到困惑和沮丧 - 任何观点或变通方法都会受到赞赏。

/ Users / johncneal / Dropbox / JN Astronomy / Astronomy / Spectroscopy / RSpec_Analyses / Gamma_Cas / 20161203 / Gamma Cas_065.fit

/ Users / johncneal / Dropbox / JN Astronomy / Astronomy / Spectroscopy / RSpec_Analyses / Gamma_Cas / 20161203 / Gamma Cas_065.fit

2 个答案:

答案 0 :(得分:0)

FileHandle初始值设定项没有很好的命名。

您应该使用FileHandle(forReadingFrom:URL)代替FileHandle(forReadingAtPath:String)。前者是更新的API,抛出错误而不是返回nil。您可以使用抛出的错误来查看失败的原因,并确保您的变量为非零。

例如:

@IBAction func btnProcFile(_ sender: Any) {

    do {
        let fileUrl = URL(fileURLWithPath:"/Users/johncneal/Dropbox/JN Astronomy/Astronomy/Spectroscopy/RSpec_Analyses/Gamma_Cas/20161203/Gamma Cas_065.fit")

        let fileHandle = try FileHandle(forReadingFrom: fileUrl)
        fileHandle.seek(toFileOffset: 2880) //skip past the headers

        let dataLenToRead = 1391 * 1039 * 2
        let data: Data = fileHandle.readData(ofLength: dataLenToRead)
        // etc...
    } catch let error as NSError {
        print("FITFile >>> File open failed: \(error)")
        NSApp.presentError(error)
    }

}

答案 1 :(得分:0)

找到答案 - 沙盒!!

Darren - 巧合的是,我确实查看了基于URL的路线并发现它“抛出”了一些适当的错误报告。很低,看到他们报道我没有对该文件的权限(最初让我感到惊讶,因为我显然是我的Mac上的管理员以及所有文件都在本地和我的用户名下。

我发现了更多的研究。这篇文章 - https://forums.developer.apple.com/thread/96062很快就揭示了它的沙盒问题:-)看起来最近版本的XCode在“权利”中打开了它。帖子还指出NSOpenPanel FileOpen对话框返回'Security scoped urls'。起初我认为这解释了为什么第一个函数中的代码有效,但我并不完全相信,因为我只是将url.path属性提供给FileHandle。

但是,在Entitlements中关闭Sandbox可以使一切正常。是的,我知道长期做的不是正确的事(或者如果我想要这个去App Store),那么我将检查正确的方法来做到这一点。至少我现在可以继续 - 感谢输入。