Как я могу узнать, когда FileHandle больше нечего читать? - PullRequest
0 голосов
/ 14 сентября 2018

Я пытаюсь использовать Pipe s fileHandleForReading s readabilityHandler, чтобы прочитать оба standardOutput и standardError из Process. Однако момент вызова terminationHandler фактически до момента, когда мой readabilityHandler вызывается впервые.

Я не уверен, почему процесс делает это, но это означает, что я не получаю все данные, потому что я предполагаю, что завершение процесса означает, что весь вывод был сброшен в канал. Поскольку это не так, есть ли способ сообщить мне, когда больше нет выходных данных для чтения? Я предполагаю, что это включает проверку, все еще ли FileHandle открыто, но я не вижу API для этого.

Вот пример базовой идеи о том, как выглядит мой код:

let stdOutPipe = Pipe()
let stdErrPipe = Pipe()

stdOutPipe.fileHandleForReading.readabilityHandler = { stdOutFileHandle in
    let stdOutPartialData = stdOutFileHandle.readDataToEndOfFile()

    guard !stdOutPartialData.isEmpty else {
        print("Time to read, but nothing to be read?") // happens a lot
        return
    }

    self.tempStdOutStorage.append(stdOutPartialData)
}

stdErrPipe.fileHandleForReading.readabilityHandler = { stdErrFileHandle in
    let stdErrPartialData = stdErrFileHandle.readDataToEndOfFile()

    guard !stdErrPartialData.isEmpty else {
        print("Time to read, but nothing to be read?") // happens a lot
        return
    }

    self.tempStdErrStorage.append(stdErrPartialData)
}

process.standardOutput = stdOutPipe
process.standardError = stdErrPipe


process.terminationHandler = { process in
    notifyOfCompleteRead(stdOut: self.tempStdOutStorage, stdErr: self.tempStdErrStorage)
}

mySpecializedDispatchQueue.async(execute: process.launch)

1 Ответ

0 голосов
/ 14 сентября 2018

В readabilityHandler вы должны использовать availableData для получения текущих доступных данных без блокировки.Пустые доступные данные указывают EOF на дескрипторе файла, в этом случае обработчик читабельности должен быть удален.

Можно использовать группу диспетчеризации для ожидания EOF как для стандартного вывода, так и для стандартной ошибки после завершения процесса.

Пример:

let group = DispatchGroup()

group.enter()
stdOutPipe.fileHandleForReading.readabilityHandler = { stdOutFileHandle in
    let stdOutPartialData = stdOutFileHandle.availableData
    if stdOutPartialData.isEmpty  {
        print("EOF on stdin")
        stdOutPipe.fileHandleForReading.readabilityHandler = nil
        group.leave()
    } else {
        tempStdOutStorage.append(stdOutPartialData)
    }
}

group.enter()
stdErrPipe.fileHandleForReading.readabilityHandler = { stdErrFileHandle in
    let stdErrPartialData = stdErrFileHandle.availableData

    if stdErrPartialData.isEmpty  {
        print("EOF on stderr")
        stdErrPipe.fileHandleForReading.readabilityHandler = nil
        group.leave()
    } else {
        tempStdErrStorage.append(stdErrPartialData)
    }
}

process.standardOutput = stdOutPipe
process.standardError = stdErrPipe

process.launch()

process.terminationHandler = { process in
    group.wait()
    print("OUTPUT:", String(data: tempStdOutStorage, encoding: .utf8)!)
    print("ERROR: ", String(data: tempStdErrStorage, encoding: .utf8)!)
}
...