如何使用NSFileHandle的readabilityHandler检查文件结尾?

时间:2013-04-06 13:12:53

标签: objective-c macos cocoa nsfilehandle

我正在使用NSFileHandle块从NSPipe(来自readabilityHandler)读取数据:

fileHandle.readabilityHandler = ^( NSFileHandle *handle ) {
     [self processData: [handle availableData]];
}

这很好用,我得到了我期望用于processData方法的所有数据。问题是我需要知道何时读取了最后一块数据。 availableData如果到达文件末尾,则应该返回一个空的NSData实例,但问题是在EOF上不再调用可达性处理程序。

我找不到任何关于如何在EOF上获得某种通知或回调的信息。那我错过了什么? Apple是否真的提供了一个没有EOF回调的异步读取API?

顺便说一下,我不能使用基于runloop的readInBackgroundAndNotify方法,因为我没有可用的runloop。如果我无法使用NSFileHandle API,我可能会直接使用调度源来执行IO。

3 个答案:

答案 0 :(得分:1)

如果您无法使用NSFileHandle,我担心如果您使用readInBackgroundAndNotify,请执行此操作。

我看到两种解决方案:

  1. 创建一个runloop,然后使用readInBackgroundAndNotify
  2. 使用dispatch_io_*
  3. 滚动您自己的实施

答案 1 :(得分:1)

我相信接受的答案实际上是不正确的。到达EOF时,确实会调用readabilityHandler。这是通过将availableData的大小设置为0来表示的。

这是一个证明这一点的简单游乐场。

import Foundation
import PlaygroundSupport

let pipe = Pipe()
pipe.fileHandleForReading.readabilityHandler = { fh in 
    let d = fh.availableData
    print("Data length: \(d.count)")
    if (d.count == 0) {
        fh.readabilityHandler = nil
    }
}
pipe.fileHandleForWriting.write("Hello".data(using: .utf8)!)
pipe.fileHandleForWriting.closeFile()

PlaygroundPage.current.needsIndefiniteExecution = true

答案 2 :(得分:0)

我个人将当前文件的偏移量与当前文件的位置进行比较,然后停止读取。

extension FileHandle {
    func stopReadingIfPassedEOF() {
        let pos = offsetInFile
        let len = seekToEndOfFile()
        if pos < len {
            // Resume reading.
            seek(toFileOffset: pos)
        }
        else {
            // Stop.
            // File offset pointer stays at the EOF.
            readabilityHandler = nil
        }
    }
}

我不明白为什么这么长时间设计它,但是现在我认为这可能是故意的。

我认为,Apple基本上将FileHandle定义为无限流,因此,除非关闭文件,否则EOF定义不明确。 FileHandle似乎更像是一个“渠道”。

当您从文件中读取数据时,如果另一个进程向文件中添加/删除一些数据,会发生什么,也不清楚。在这种情况下,EOF是多少?据我所知,Apple文档中没有提及这种情况。据我所知,在macOS中没有像其他类似Unix的系统那样真正的排他文件I / O锁定。

我认为,如果I / O不够快,availableData可以随时返回空数据,而readabilityHandler只是在乎EOF。