关于如何从流程流中读取已有few answers,但据我所知,它们不包括从以下流程中读取:
因此,使用上述解决方案会导致浪费的进程周期,因为即使没有输出,循环也会尝试读取流,或者由于进程无法打印整个输出而导致解决方案无法终止(由于完整缓冲区)输出处理程序在读取之前等待进程终止。
我目前的解决方案看起来像这样(受批量阅读大文件的解决方案的启发)
(defun control-process (process timeout)
(sb-ext:with-timeout timeout
(handler-case
(do ((output-stream (sb-ext:process-output process))
(string nil))
((and (equalp (sb-ext:process-status process) :exited)
(equalp (peek-char nil output-stream nil :eof) :eof))
(values string :exited))
(cond
((equalp (sb-ext:process-status process) :signaled)
(error 'unexpected-process-finish :finish-status :signaled))
((equalp (sb-ext:process-status process) :stopped)
(error 'unexpected-process-finish :finish-status :stopped)))
(let ((seq (make-string (file-length output-stream))))
(read-sequence seq output-stream)
(setf string (concatenate 'string string seq))
(sleep 1)))
(sb-ext:timeout (err)
(declare (ignore err))
(values nil :timeout))
(unexpected-process-finish (err)
(values nil (finish-status err))))))
使用以下过程调用该函数:
(sb-ext:run-program "/path/to/programm"
(list "--params" "foo" "bar")
:output :stream :wait nil)
但这种解决方案有其缺点:
调用函数处理退出/停止/运行时间过长的最终处理/清理。
我如何阅读以下流程:
答案 0 :(得分:5)
字符串输出流可能适合您吗?输出将存储在您之后获得的字符串中,因此缓冲不应该是一个太大的问题。例如,
* (with-output-to-string (out)
(sb-ext:run-program "/bin/ls" '("/") :output out))
"bin
boot
…
vmlinuz
vmlinuz.old
"
如果您想预先分配字符串,可以使用with-output-to-string的 string-form 参数来执行该操作。
但是,您不必使用with-output-to-string来使用字符串输出流。您也可以使用make-string-output-stream创建一个并将其传递给sb-ext:run-program。您最终会使用get-output-stream-string获取文本。