首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在Swift中使用"tee“NSPipe

如何在Swift中使用"tee“NSPipe
EN

Stack Overflow用户
提问于 2016-08-09 13:44:07
回答 1查看 204关注 0票数 1

我正在尝试使用标准输出NSPipe ( NSTask的一个)来获得两个NSPipes,每个NSPipes将进入两个新的NSTasks的标准输入。

我知道我可以用函数在C中做到这一点,但我在基金会和达尔文框架中都找不到它。我怎样才能做到这一点?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-05-23 20:10:15

我写了一个解决方案,它在我的项目中运行得很好。我已经提供了一个Swift软件包,论GitHub。您也可以在那里找到使用它的例子。以下是代码:

代码语言:javascript
复制
/**
 Duplicates the data from `input` into each of the `outputs`.
 Following the precedent of `standardInput`/`standardOutput`/`standardError` in `Process` from `Foundation`,
    we accept the type `Any`, but throw a precondition failure if the arguments are not of type `Pipe` or `FileHandle`.
 https://github.com/apple/swift-corelibs-foundation/blob/eec4b26deee34edb7664ddd9c1222492a399d122/Sources/Foundation/Process.swift
 When `input` sends an EOF (write of length 0), the `outputs` file handles are closed, so only output to handles you own.
 This function sets the `readabilityHandler` of inputs and the `writeabilityHandler` of outputs,
    so you should not set these yourself after calling `tee`.
 The one exception to this guidance is that you can set the `readabilityHandler` of `input` to `nil` to stop `tee`ing.
 After doing so, the `writeabilityHandler`s of the `output`s will be set to `nil` automatically after all in-progress writes complete,
    but if desired, you could set them to `nil` manually to cancel these writes. However, this may result in some outputs recieving less of the data than others.
 This implementation waits for all outputs to consume a piece of input before more input is read.
 This means that the speed at which your processes read data may be bottlenecked by the speed at which the slowest process reads data,
    but this method also comes with very little memory overhead and is easy to cancel.
 If this is unacceptable for your use case. you may wish to rewrite this with a data deque for each output.
 */
public func tee(from input: Any, into outputs: Any...) {
    tee(from: input, into: outputs)
}
public func tee(from input: Any, into outputs: [Any]) {
    /// Get reading and writing handles from the input and outputs respectively.
    guard let input = fileHandleForReading(input) else {
        preconditionFailure(incorrectTypeMessage)
    }
    let outputs: [FileHandle] = outputs.map({
        guard let output = fileHandleForWriting($0) else {
            preconditionFailure(incorrectTypeMessage)
        }
        return output
    })
    
    let writeGroup = DispatchGroup()
    
    input.readabilityHandler = { input in
        let data = input.availableData
        
        /// If the data is empty, EOF reached
        guard !data.isEmpty else {
            /// Close all the outputs
            for output in outputs {
                output.closeFile()
            }
            /// Stop reading and return
            input.readabilityHandler = nil
            return
        }
        
        for output in outputs {
            /// Tell `writeGroup` to wait on this output.
            writeGroup.enter()
            output.writeabilityHandler = { output in
                /// Synchronously write the data
                output.write(data)
                /// Signal that we do not need to write anymore
                output.writeabilityHandler = nil
                /// Inform `writeGroup` that we are done.
                writeGroup.leave()
            }
        }
        
        /// Wait until all outputs have recieved the data
        writeGroup.wait()
    }
}

/// The message that is passed to `preconditionFailure` when an incorrect type is passed to `tee`.
let incorrectTypeMessage = "Arguments of tee must be either Pipe or FileHandle."

/// Get a file handle for reading from a `Pipe` or the handle itself from a `FileHandle`, or `nil` otherwise.
func fileHandleForReading(_ handle: Any) -> FileHandle? {
    switch handle {
    case let pipe as Pipe:
        return pipe.fileHandleForReading
    case let file as FileHandle:
        return file
    default:
        return nil
    }
}
/// Get a file handle for writing from a `Pipe` or the handle itself from a `FileHandle`, or `nil` otherwise.
func fileHandleForWriting(_ handle: Any) -> FileHandle? {
    switch handle {
    case let pipe as Pipe:
        return pipe.fileHandleForWriting
    case let file as FileHandle:
        return file
    default:
        return nil
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38852518

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档