Swift 如何";“三通”;斯威夫特管道

Swift 如何";“三通”;斯威夫特管道,swift,foundation,tee,darwin,nspipe,Swift,Foundation,Tee,Darwin,Nspipe,我正在尝试将NSTask的标准输出NSPipe one T接成两个NSPipe,每个NSPipe都将进入两个新NSTask的标准输入 我知道我可以用C做这个,但是我找不到基础和达尔文框架。如何实现这一点?我为此编写了一个解决方案,它在我的项目中运行良好。我已经准备了一个快捷的包裹。你也可以在那里找到使用它的例子。代码如下: /** 将“输入”中的数据复制到每个“输出”中。 遵循“基础”中“过程”中的“标准输入”/“标准输出”/“标准错误”的先例, 我们接受“Any”类型,但如果参数不是“Pipe

我正在尝试将NSTask的标准输出NSPipe one T接成两个NSPipe,每个NSPipe都将进入两个新NSTask的标准输入


我知道我可以用C做这个,但是我找不到基础和达尔文框架。如何实现这一点?

我为此编写了一个解决方案,它在我的项目中运行良好。我已经准备了一个快捷的包裹。你也可以在那里找到使用它的例子。代码如下:

/**
将“输入”中的数据复制到每个“输出”中。
遵循“基础”中“过程”中的“标准输入”/“标准输出”/“标准错误”的先例,
我们接受“Any”类型,但如果参数不是“Pipe”或“FileHandle”类型,则抛出一个前置条件失败。
https://github.com/apple/swift-corelibs-foundation/blob/eec4b26deee34edb7664ddd9c1222492a399d122/Sources/Foundation/Process.swift
当'input'发送一个EOF(写入长度为0)时,'outputs'文件句柄关闭,因此仅输出到您自己的句柄。
此函数用于设置输入的“readabilityHandler”和输出的“writeabilityHandler”,
因此,您不应该在调用“tee”后自行设置这些参数。
本指南的一个例外是,您可以将'input'的'readabilityHandler'设置为'nil'以停止'tee'操作。
执行此操作后,“output”的“WriteableHandler”将在所有进行中的写入完成后自动设置为“nil”,
但如果需要,您可以手动将其设置为“nil”以取消这些写入。然而,这可能导致某些输出接收的数据比其他输出少。
此实现在读取更多输入之前,等待所有输出消耗一段输入。
这意味着进程读取数据的速度可能会受到最慢进程读取数据速度的限制,
但是,这种方法也具有很少的内存开销,并且很容易取消。
如果这对于您的用例是不可接受的。您可能希望用每个输出的数据deque重写此命令。
*/
公共函数T(从输入:任意,到输出:任意…){
T形三通(从:输入,到:输出)
}
公共函数T(从输入:任意,到输出:[任意]){
///分别从输入和输出获取读取和写入句柄。
guard let input=fileHandleForReading(输入)else{
预处理失败(不正确的类型消息)
}
let outputs:[FileHandle]=outputs.map({
guard let output=fileHandleForWriting($0)else{
预处理失败(不正确的类型消息)
}
返回输出
})
让writeGroup=DispatchGroup()
input.readabilityHandler={input in
让数据=input.availableData
///如果数据为空,则达到EOF
守卫!数据。我还有空吗{
///关闭所有输出
输出中的输出{
output.closeFile()文件
}
///停止阅读并返回
input.readabilityHandler=nil
返回
}
输出中的输出{
///告诉'writeGroup'等待此输出。
writeGroup.enter()
output.writeabilityHandler={output in
///同步写入数据
输出.写入(数据)
///表示我们不需要再写了
output.writeabilityHandler=nil
///通知writeGroup我们已经完成了。
writeGroup.leave()
}
}
///等待所有输出接收到数据
writeGroup.wait()
}
}
///将不正确的类型传递给“tee”时传递给“PremissionFailure”的消息。
let incorrectTypeMessage=“T形三通的参数必须是管道或文件句柄。”
///获取用于从'Pipe'读取的文件句柄,或从'FileHandle'获取句柄本身,或获取'nil'其他内容。
func fileHandleForReading(handle:Any)->FileHandle?{
开关手柄{
套管作为管道:
返回管道.fileHandleForReading
案例let文件作为FileHandle:
返回文件
违约:
归零
}
}
///从'Pipe'获取用于写入的文件句柄,或从'FileHandle'获取句柄本身,否则为'nil'。
func fileHandleForWriting(handle:Any)->FileHandle?{
开关手柄{
套管作为管道:
返回管道.fileHandleForWriting
案例let文件作为FileHandle:
返回文件
违约:
归零
}
}

那么最好的方法就是用C语言编写,并使用桥接头。我想我可以这样做。但奇怪的是,我可以看到
fcntl.h
头的其他成员,比如
Darwin
模块中的
fcntl()
,但没有
tee()
,除非我弄错了,OSX没有
tee
系统调用或库函数,只有
/usr/bin/tee
命令。@MartinR有趣,所以我必须用
read()
/
write()
循环来实现我自己的功能?@MartinR你认为实现这一点最好的方法是什么?(调用两个不同的NSTask来处理另一个NSTask的输入)请注意,您不应该关闭
FileHandle.standardOutput
和friends,因此需要修改此代码才能使用它们。我添加了控制何时将句柄释放到git repo的功能。