为啥 FileHandle 不一致地返回“nil”
Posted
技术标签:
【中文标题】为啥 FileHandle 不一致地返回“nil”【英文标题】:Why is FileHandle inconsistently returning 'nil'为什么 FileHandle 不一致地返回“nil” 【发布时间】:2018-05-31 20:57:44 【问题描述】:我有一个应用程序在使用 FileHandle 打开文件进行读取时不一致地返回“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))!
:
:
这些文件还包含我在应用程序的另一部分处理的二进制数据块。当我为此开发代码时,出于测试目的,我暂时对与上述工作相同的文件名之一进行硬编码。但是这段代码(如下)总是抛出异常'Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value' 当它到达 fileHandle?.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()'ing 提供给 FileHandle() 的文件名表明它们在每种情况下都是相同的(见下文)。所以我对此感到困惑和沮丧 - 任何观点或解决方法都会受到赞赏。
/Users/johncneal/Dropbox/JN 天文学/天文学/光谱学/RSpec_Analyses/Gamma_Cas/20161203/Gamma Cas_065.fit
/Users/johncneal/Dropbox/JN 天文学/天文学/光谱学/RSpec_Analyses/Gamma_Cas/20161203/Gamma Cas_065.fit
【问题讨论】:
如果fileHandle
是nil
,则fileHandle?.seek
行不能抛出该错误。使用调试器。如果fileHandle
真的是nil
?
【参考方案1】:
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)
【讨论】:
虽然这都是很好的建议,但请记住,如果fileHandle
是 nil
,则 OP 的代码不会导致所述错误,因为在调用 seek
时使用了可选链接。 【参考方案2】:
找到答案 - 沙盒!!
Darren - 巧合的是,我确实查看了基于 URL 的路由,发现它“抛出”了一些适当的错误报告。低,他们报告说我没有文件的权限(这最初让我感到惊讶,因为我显然是我的 Mac 上的管理员,所有文件都是本地的,并且在我的用户名下。
我做了更多的研究。这篇文章 - https://forums.developer.apple.com/thread/96062 很快揭示了它的沙盒问题:-) 看起来最近版本的 XCode 在“权利”中打开了它。该帖子还指出 NSOpenPanel FileOpen 对话框返回“Security scoped urls”。起初我认为这解释了为什么第一个函数中的代码有效,但我并不完全相信,因为我只是将 url.path 属性提供给 FileHandle。
但是,在权利中关闭沙盒可以让一切正常。是的,我知道这不是长期做的正确事情(或者如果我想让它进入 App Store),所以我会检查正确的方法来做到这一点。至少我现在可以继续 - 感谢您的意见。
【讨论】:
以上是关于为啥 FileHandle 不一致地返回“nil”的主要内容,如果未能解决你的问题,请参考以下文章
为啥 NSFormatter dateFromString 偶尔会返回 nil?