2012-01-11 11 views
5

Tôi đang cố gắng chạy một chương trình bên ngoài trong SBCL và nắm bắt đầu ra của nó. Đầu ra là dữ liệu nhị phân (hình ảnh png), trong khi SBCL nhấn mạnh việc diễn giải nó dưới dạng chuỗi.Đọc đầu ra nhị phân của một chương trình bên ngoài trong Common Lisp

Tôi đã thử một số cách khác nhau, như

(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)) 

Nhưng tôi nhận được lỗi như

Illegal :UTF-8 character starting at byte position 0. 

Dường như với tôi rằng SBCL đang cố gắng để giải thích các dữ liệu nhị phân như một văn bản và giải mã nó . Làm cách nào để thay đổi hành vi này? Tôi chỉ quan tâm đến việc có được một vec tơ octet.

Chỉnh sửa: Vì nó không rõ ràng từ văn bản ở trên, tôi muốn thêm rằng ít nhất là trong trường hợp của dòng flexi, loại phần tử của luồng là flexi-streams:octect (là (unsigned-byte 8)). Tôi mong đợi ít nhất trong trường hợp này là run-program để đọc các byte thô mà không có nhiều vấn đề. Thay vào đó, tôi nhận được thông báo như Don't know how to copy to stream of element-type (UNSIGNED-BYTE 8)

Trả lời

4

Chỉnh sửa: Tôi rất tức giận khi không thể thực hiện tác vụ rất đơn giản này và giải quyết được sự cố.

Chức năng, khả năng gửi luồng loại UNSIGNED-BYTE vào chương trình chạy và hoạt động chính xác bị hạn chế nghiêm trọng, vì các lý do tôi không hiểu. Tôi đã thử các luồng màu xám, các dòng flexi, các luồng fd và một vài cơ chế khác, như bạn.

Tuy nhiên, nguồn chương trình chạy thử (cho lần thứ năm hoặc thứ sáu), tôi nhận thấy rằng có một tùy chọn: STREAM bạn có thể chuyển đến đầu ra. Cho rằng, tôi tự hỏi nếu đọc-byte sẽ làm việc ... và nó đã làm. Để làm việc hiệu quả hơn, người ta có thể xác định cách lấy độ dài của luồng không phải là tệp và chạy READ-SEQUENCE trên nó.

(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)))) 
+0

Có, điều này dường như hoạt động, cảm ơn bạn rất nhiều! Trong mọi trường hợp tôi không chắc chắn vấn đề nằm ở đâu. Tôi có nghĩa là, bằng cách sử dụng một dòng tập tin như đầu ra hoạt động tốt, do đó, vấn đề không hoàn toàn trong chương trình chạy, mà là trên sự tương tác giữa một dòng chuỗi và chạy chương trình. Nhưng tôi hy vọng rằng việc sử dụng với đầu ra-to-sequence sẽ hoạt động tốt. Dù sao thì ít nhất tôi cũng có một giải pháp. Cảm ơn một lần nữa. –

+0

@MarcoRighele: trên SO, nếu bạn quan tâm để chấp nhận câu trả lời, nó đánh dấu câu hỏi như được trả lời trong hệ thống SO - đó là dấu kiểm của các nút bỏ phiếu. –

+0

Nếu bạn đang chờ xem liệu giải pháp kia có đang hoạt động hay không. Trong mọi trường hợp tôi thích cái này vì nó có ít phụ thuộc bên ngoài hơn. –

2

Nếu bạn sẵn sàng sử dụng một số thư viện bên ngoài, điều này có thể được thực hiện với luồng babel. Đây là một hàm tôi sử dụng để lấy nội dung một cách an toàn từ một chương trình. Tôi sử dụng: latin-1 vì nó ánh xạ 256 byte đầu tiên chỉ với các ký tự. Bạn có thể loại bỏ các octet-to-string và có vector.

Nếu bạn muốn stderr là tốt, bạn có thể sử dụng lồng nhau 'with-output-to-sequence' để có được cả hai.

(defun safe-shell (command &rest args)                           
    (octets-to-string                                
    (with-output-to-sequence (stream :external-format :latin-1)                     
    (let ((proc (sb-ext:run-program command args :search t :wait t :output stream)))                
     (case (sb-ext:process-status proc)                           
     (:exited (unless (zerop (sb-ext:process-exit-code proc))                     
        (error "Error in command")))                         
     (t (error "Unable to terminate process")))))                        
    :encoding :latin-1))                               
+0

Tôi gặp sự cố khi chạy ví dụ của bạn. Với SBCL dưới Linux tôi nhận được cảnh báo: ENCODING không phải là một từ khóa đối số đã biết, và trình bao an toàn đang chạy cho tôi "Mã hóa ký tự không xác định: # ". Tui bỏ lỡ điều gì vậy ? –

+0

Không hoàn toàn chắc chắn nếu không biết phiên bản của SBCL và babel bạn đang sử dụng. Bạn có thể thử: iso-8859-1, vì đó là tên kinh điển cho nó. Đảm bảo rằng OCTETS-TO-STRING đến từ BABLE. –

+0

Ah có, tôi đã sử dụng sb-ext: octects-to-string. Với chức năng phù hợp và phiên bản mới nhất của sbcl có vẻ như hoạt động chính xác. Cảm ơn nhiều. –

2

Paul Nathan đã đưa ra một câu trả lời khá hoàn chỉnh như để cách để đọc I/O từ một chương trình như nhị phân, vì vậy tôi sẽ chỉ cần thêm tại sao mã của bạn không làm việc: bởi vì bạn được yêu cầu một cách rõ ràng SBCL để diễn giải I/O dưới dạng chuỗi ký tự UTF-8, sử dụng with-{in,out}put-to-string.

Ngoài ra, tôi muốn chỉ ra rằng bạn không cần phải đi xa như mã nguồn của run-program để truy cập giải pháp. Nó được ghi rõ trong SBCL's manual.

+0

Đó là sự thật cho 'with-output-to-string' (tất nhiên là có kiểu phần tử của' character'), nhưng không phải cho trường hợp dòng flexi, nơi luồng được tạo bởi octects. Tôi mong rằng chương trình chạy sẽ đọc các phần tử của 'loại phần tử' đúng tùy thuộc vào luồng, nhưng có vẻ như đó không phải là trường hợp. Dù sao, bây giờ tôi nhận ra rằng các ví dụ không rõ ràng lắm, tôi sẽ đưa thêm một số thông tin lỗi kết thúc chi tiết –

+0

Nhưng bạn sẽ lưu ý rằng bạn không gặp lỗi tương tự với các dòng linh hoạt. Nếu bạn nhìn vào thông báo lỗi và theo dõi ngăn xếp, bạn sẽ thấy rằng một dự đoán công bằng là SBCL không sử dụng bất kỳ chức năng ghi nào nhưng một số tối ưu hóa triển khai cụ thể và không thành công với dòng flexi. –