【问题标题】:How to check for End-of-File using NSFileHandle's readabilityHandler?如何使用 NSFileHandle 的 readabilityHandler 检查文件结尾?
【发布时间】:2013-04-06 13:12:52
【问题描述】:

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

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

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

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

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

【问题讨论】:

  • 您确定管道的所有写入端都已关闭吗?关于运行循环,所有线程都会按需创建一个运行循环,您可以自己运行一个。
  • 是的,管道已正确关闭。我做了一些更多的实验,同样的事情也发生在其他类型的 NSFileHandle 实例上。从标准输入或常规文件读取时,也没有 EOF 通知。

标签: objective-c macos cocoa nsfilehandle


【解决方案1】:

我个人比较当前文件偏移和当前文件位置并停止读取。

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。

【讨论】:

    【解决方案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
    

    【讨论】:

    • 我遇到了同样的行为。这就是我一直在检测 EOF 的方式,并且它一直在工作。
    【解决方案3】:

    如果您不能使用 readInBackgroundAndNotify,恐怕您在使用 NSFileHandle 时会不走运。

    我看到的两个解决方案:

    1. 创建一个运行循环,然后使用readInBackgroundAndNotify
    2. 使用dispatch_io_* 滚动您自己的实现

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-14
      • 1970-01-01
      • 2015-03-22
      • 2011-11-22
      • 2019-05-10
      • 2013-03-13
      相关资源
      最近更新 更多