在Common Lisp中读取外部程序的二进制输出

Mar*_*ele 5 sbcl common-lisp stream

我正在尝试在SBCL中运行外部程序并捕获其输出.输出是二进制数据(png图像),而SBCL坚持将其解释为字符串.

我试过很多方法,比如

(trivial-shell:shell-command "/path/to/png-generator" :input "some input")

(with-input-from-string (input "some input")
  (with-output-to-string (output)
    (run-program "/path/to/png-generator" () :input input :output output))


(with-input-from-string (input "some input")
  (flexi-streams:with-output-to-sequence (output)
    (run-program "/path/to/png-generator" () :input input :output output))
Run Code Online (Sandbox Code Playgroud)

但我得到的错误就像

Illegal :UTF-8 character starting at byte position 0.
Run Code Online (Sandbox Code Playgroud)

在我看来,SBCL正试图将二进制数据解释为文本并对其进行解码.我该如何改变这种行为?我只对获取八位字节的向量感兴趣.

编辑:由于上面的文字不清楚,我想补充一点,至少在flexi-stream的情况下,流的元素类型是a flexi-streams:octect(这是a (unsigned-byte 8)).我希望至少在这种情况下run-program读取原始字节没有很多问题.相反,我收到了一条消息Don't know how to copy to stream of element-type (UNSIGNED-BYTE 8)

Pau*_*han 5

编辑:我对无法完成这个非常简单的任务感到生气并解决了这个问题。

从功能上讲,由于我不明白的原因,将 UNSIGNED-BYTE 类型的流发送到运行程序并使其正常工作的能力受到严重限制。我尝试了灰色流、灵活流、fd 流和其他一些机制,就像你一样。

但是,仔细阅读 run-program 的源代码(第五次或第六次),我注意到有一个选项 :STREAM 您可以传递给输出。鉴于此,我想知道 read-byte 是否会起作用……它确实起作用了。对于更高性能的工作,可以确定如何获取非文件流的长度并对其运行 READ-SEQUENCE。

(let* 
       ;; Get random bytes
      ((proc-var (sb-ext:run-program "head" '("-c" "10" "/dev/urandom")
                                     :search t
       ;; let SBCL figure out the storage type. This is what solved the problem.
                                     :output :stream))
       ;; Obtain the streams from the process object.
       (output (process-output proc-var))
       (err (process-error proc-var)))
  (values
   ;;return both stdout and stderr, just for polish.
   ;; do a byte read and turn it into a vector.
   (concatenate 'vector
                ;; A byte with value 0 is *not* value nil. Yay for Lisp!
                (loop for byte = (read-byte output nil)
                   while byte
                   collect byte))
   ;; repeat for stderr
   (concatenate 'vector
                (loop for byte = (read-byte err nil)
                   while byte
                   collect byte))))
Run Code Online (Sandbox Code Playgroud)