简体   繁体   English

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

[英]How to check for End-of-File using NSFileHandle's readabilityHandler?

I am reading data from a NSFileHandle (from a NSPipe ) using a readabilityHandler block:我正在使用NSPipe块从NSFileHandle (来自NSPipereadabilityHandler数据:

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

This works fine, I get all the data I expect fed to my processData method.这很好用,我得到了我期望输入到我的processData方法的所有数据。 The problem is that I need to know when the last chunk of data was read.问题是我需要知道最后一块数据是什么时候读取的。 availableData should return an empty NSData instance if it reached end-of-file, but the problem is that the reachability handler is not called again on EOF. availableData到达文件结尾,则它应该返回一个空的NSData实例,但问题是在 EOF 上不会再次调用可达性处理程序。

I can't find anything about how to get some kind of notification or callback on EOF.我找不到有关如何在 EOF 上获得某种通知或回调的任何信息。 So what am I missing?那么我错过了什么? Is Apple really providing an asynchronous reading API without an EOF callback?苹果真的提供了没有 EOF 回调的异步读取 API 吗?

By the way, I cannot use the runloop based readInBackgroundAndNotify method since I don't have a runloop available.顺便说一下,我不能使用基于readInBackgroundAndNotify方法,因为我没有可用的 runloop。 If I cannot get this to work with the NSFileHandle API I probably will directly use a dispatch source to do the IO.如果我不能NSFileHandleNSFileHandle API 一起工作,我可能会直接使用调度源来执行 IO。

I personally compare current file offset with current file position and stop reading.我个人将当前文件偏移量与当前文件位置进行比较并停止阅读。

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
        }
    }
}

I couldn't understand why it's been designed in this way for a long time, but now I think this could be intentional.很长一段时间我都无法理解为什么它是这样设计的,但现在我认为这可能是故意的。

In my opinion, Apple basically defines FileHandle as an infinite stream, therefore, EOF is not well defined unless you close the file.在我看来,Apple 基本上将FileHandle定义为无限流,因此,除非您关闭文件,否则 EOF 定义不明确。 FileHandle seem to be more like a "channel". FileHandle似乎更像是一个“通道”。

It's also unclear what happens if another process appends/delete some data to/from the file while you're reading from it.还不清楚如果另一个进程在您读取文件时向文件中添加/删除一些数据/从文件中删除会发生什么。 What would be the EOF in this case?在这种情况下,EOF 是什么? As far as I find, there's no mention about this case in Apple documentation.据我所知,Apple 文档中没有提及此案例。 As far as I know, there's no true exclusive file I/O lock in macOS like other Unix-like systems.据我所知,macOS 中没有像其他类 Unix 系统那样真正的独占文件 I/O 锁。

In my opinion, availableData can return empty data at any time if I/O is not fast enough, and readabilityHandler just don't care about EOF.在我看来,如果 I/O 不够快, availableData可以随时返回空数据,而readabilityHandler只是不关心 EOF。

I believe the accepted answer is actually incorrect.我相信接受的答案实际上是不正确的。 The readabilityHandler is indeed called when EOF is reached.当达到 EOF 时确实会调用 readabilityHandler。 That is signaled by having availableData be of 0 size.这是通过使 availableData 的大小为 0 来表示的。

Here's a simple playground that attests to this.这是一个简单的操场证明了这一点。

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

I'm afraid you're out of luck doing this with NSFileHandle if you can't use readInBackgroundAndNotify .如果你不能使用readInBackgroundAndNotify恐怕你不走运NSFileHandle这样做。

Two solutions I see:我看到的两种解决方案:

  1. Create a runloop and then use readInBackgroundAndNotify .创建一个 runloop,然后使用readInBackgroundAndNotify
  2. Roll your own implementation using dispatch_io_*使用dispatch_io_*滚动你自己的实现

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM