Pipe() 是 Swift(Foundation 框架)中的一个类,用于在程序和子进程之间创建双向通信通道,本质上是一个数据管道,可以用来:
1、读取子进程的输出(standardOutput)
2、捕获子进程的错误信息(standardError)
3、向子进程写入数据(standardInput)
Pipe 是 Foundation 提供的类,背后基于 Unix 的底层 pipe() 系统调用。
可以把Pipe理解为一个中转通道,把它插在 Process(进程命令)的输出口上,它就能把进程中的内容“接管”出来,供使用 Swift 来读取或处理。

常用属性和方法
1、fileHandleForReading:用来从管道中读取数据(子进程输出)。
process.standardOutput = pipe
let fileHandle = pipe.fileHandleForReading
let logData = fileHandle.readDataToEndOfFile()
if let log = String(data: logData, encoding: .utf8) {
print("pngquant 日志:\n\(log)")
}
这是子进程中读取输出的主要手段,通常用来绑定 standardOutput 或 standardError:
2、fileHandleForWriting:用来写入数据(发送到子进程输入)。
process.standardInput = pipe
let input = "Hello\n".data(using: .utf8)!
pipe.fileHandleForWriting.write(input)
适合场景:子进程是 read, cat, python 这类能从 stdin 读取的命令。
3、fileHandleForReading.readDataToEndOfFile():用于同步读取全部数据,直到文件句柄关闭(也就是子进程退出)。
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8)
适合输出少、命令执行时间短的场景;
长时间运行或输出很多时,可能造成阻塞或死锁。
4、fileHandleForReading.readabilityHandler:监听数据到达事件(异步读取),每当有数据可读,系统就自动触发这个闭包。
pipe.fileHandleForReading.readabilityHandler = { handle in
let data = handle.availableData
if data.isEmpty {
print("数据读取完毕")
} else if let line = String(data: data, encoding: .utf8) {
print("实时输出:\(line)")
}
}
非阻塞,适合实时显示子进程的输出(如进度、log)。
注意:需要要主动关闭它,否则句柄不会释放:
pipe.fileHandleForReading.readabilityHandler = nil
5、availableData:用于在 readabilityHandler 中获取当前缓冲区内容。
let data = pipe.fileHandleForReading.availableData
6、write(_:):向 fileHandleForWriting 写入数据。
let input = "exit\n".data(using: .utf8)!
pipe.fileHandleForWriting.write(input)
7、closeFile():手动关闭 fileHandle,尤其在写入完毕后必须关闭,表示 EOF:
pipe.fileHandleForWriting.closeFile()
如果不关闭,有些子进程(如 cat)会一直等待输入,导致卡住。
8、readToEnd()(async/await):在 macOS 12+ 中,FileHandle 支持 async 方式读取:
if let data = try? await pipe.fileHandleForReading.readToEnd(),
let output = String(data: data, encoding: .utf8) {
print("读取到:\(output)")
}
支持现代 async/await,但需要 macOS 12+。
使用场景
1、获取命令行输出:
let pipe = Pipe()
process.standardOutput = pipe
try process.run()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8)
print("输出结果:\(output ?? "无")")
2、同时捕获错误输出:
process.standardError = pipe // 错误输出也导入 pipe
3、向子进程输入内容
let inputPipe = Pipe()
process.standardInput = inputPipe
let input = "hello\n".data(using: .utf8)!
inputPipe.fileHandleForWriting.write(input)
注意事项
管道是有缓冲区的,不能无限写入或读取;
如果用 readabilityHandler(异步监听),要注意线程和内存释放;
要确保读取在子进程退出之后完成,防止丢数据;
// Process()异步完成后的回调函数
process.terminationHandler = { process in
let logData = fileHandle.readDataToEndOfFile()
// 在完成后,输出捕获的信息,防止丢失数据
if let log = String(data: logData, encoding: .utf8) {
print("pngquant 日志:\n\(log)")
}
}
如果既捕获标准输出又捕获错误输出,通常会用两个 Pipe()(除非想统一输出)。
总结
Pipe() 是连接子进程的“数据管道”,可以读到或写入子进程中的内容。它是 Process 的好搭档,尤其适用于图片压缩、脚本执行、终端命令调用等场景。
相关文章
Swift执行进程命令Process():https://fangjunyu.com/2025/07/15/swift%e6%89%a7%e8%a1%8c%e8%bf%9b%e7%a8%8b%e5%91%bd%e4%bb%a4process/