13

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

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

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

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

顺便说一句,我不能使用基于 runloop 的readInBackgroundAndNotify方法,因为我没有可用的 runloop。如果我不能让它与NSFileHandleAPI 一起工作,我可能会直接使用调度源来执行 IO。

4

3 回答 3

3

我个人将当前文件偏移量与当前文件位置进行比较并停止阅读。

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 锁。

在我看来,availableData如果 I/O 不够快,可以随时返回空数据,而readabilityHandler不必关心 EOF。

于 2018-09-29T03:56:47.540 回答
2

我相信接受的答案实际上是不正确的。到达 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
于 2020-02-22T21:12:53.350 回答
0

如果您NSFileHandle不能使用readInBackgroundAndNotify.

我看到的两个解决方案:

  1. 创建一个运行循环,然后使用readInBackgroundAndNotify.
  2. 使用滚动您自己的实现dispatch_io_*
于 2015-02-13T09:18:23.960 回答