2012-01-11 16 views
5

में किसी बाहरी प्रोग्राम के बाइनरी आउटपुट को पढ़ना मैं एसबीसीएल में एक बाहरी प्रोग्राम चलाने और इसके आउटपुट को कैप्चर करने की कोशिश कर रहा हूं। आउटपुट द्विआधारी डेटा (एक पीएनजी छवि) है, जबकि एसबीसीएल इसे स्ट्रिंग के रूप में व्याख्या करने पर जोर देता है।सामान्य लिस्प

मैं कई तरीकों से करने की कोशिश की लेकिन

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

की तरह, मैं की तरह

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

त्रुटियों मिल मुझे ऐसा लगता है कि SBCL एक पाठ के रूप में बाइनरी डेटा की व्याख्या और यह डिकोड करने के लिए कोशिश कर रहा है । मैं इस व्यवहार को कैसे बदलूं? मुझे केवल ऑक्टेट्स के वेक्टर प्राप्त करने में दिलचस्पी है।

संपादित करें: चूंकि यह ऊपर दिए गए पाठ से स्पष्ट नहीं है, इसलिए मैं इसे कम से कम flexi-stream के मामले में जोड़ना चाहता हूं, धारा का तत्व-प्रकार flexi-streams:octect है (जो (unsigned-byte 8) है)। मैं कम से कम इस मामले मेंको कई मुद्दों के बिना कच्चे बाइट पढ़ने के लिए उम्मीद करता हूं। इसके बजाय मुझे Don't know how to copy to stream of element-type (UNSIGNED-BYTE 8)

उत्तर

4

संपादित करें: मुझे यह बहुत आसान काम करने और समस्या हल करने में सक्षम होने पर नाराज हो गया।

कार्यात्मक रूप से, रन-प्रोग्राम में UNSIGNED-BYTE प्रकार की स्ट्रीम भेजने की क्षमता और इसे सही तरीके से काम करने की क्षमता गंभीर रूप से सीमित है, जिन कारणों से मुझे समझ में नहीं आता है। मैंने ग्रे स्ट्रीम, फ्लेक्सी-स्ट्रीम, एफडी धाराएं, और आपके जैसे कुछ अन्य तंत्रों की कोशिश की।

हालांकि, रन-प्रोग्राम के स्रोत (पांचवें या छठे समय के लिए) को देखते हुए, मैंने देखा कि एक विकल्प है: स्ट्रीम आप आउटपुट में जा सकते हैं। यह देखते हुए, मुझे आश्चर्य हुआ कि क्या रीड-बाइट काम करेगा ... और ऐसा हुआ। अधिक प्रदर्शन करने वाले काम के लिए, कोई यह निर्धारित कर सकता है कि गैर-फ़ाइल स्ट्रीम की लंबाई कैसे प्राप्त करें और उस पर रीड-सेक्वेंस चलाएं।

(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

हाँ, यह काम करने लगता है, बहुत बहुत धन्यवाद! किसी भी मामले में मुझे यकीन नहीं है कि समस्या कहां है। मेरा मतलब है, आउटपुट के रूप में फ़ाइल स्ट्रीम का उपयोग करना ठीक काम करता है, इसलिए समस्या पूरी तरह से रन-प्रोग्राम में नहीं है, बल्कि स्ट्रिंग स्ट्रीम और रन-प्रोग्राम के बीच बातचीत पर है। लेकिन मैं उम्मीद करता हूं कि आउटपुट-टू-अनुक्रम का उपयोग ठीक से काम करेगा। वैसे भी कम से कम मेरे पास अब एक समाधान है। एक बार फिर धन्यवाद। –

+0

@ मार्कोरिघेल: SO पर, यदि आप एक उत्तर स्वीकार करने की परवाह करते हैं, तो यह एसओ सिस्टम में दिए गए प्रश्न को चिह्नित करता है - यह वोट बटन द्वारा चेक मार्क है। –

+0

अगर यह देखने का इंतजार कर रहा था कि दूसरा समाधान भी काम कर रहा है या नहीं। किसी भी मामले में मैं इसे पसंद करता हूं क्योंकि इसकी बाहरी निर्भरता कम होती है। –

2

यदि आप कुछ बाहरी पुस्तकालयों का उपयोग करने के इच्छुक हैं, तो यह बेबेल-स्ट्रीम के साथ किया जा सकता है। यह एक ऐसा फ़ंक्शन है जिसका उपयोग मैं सुरक्षित रूप से किसी प्रोग्राम से सामग्री प्राप्त करने के लिए करता हूं। मैं इसका उपयोग करता हूं: लैटिन -1 क्योंकि यह केवल पात्रों के लिए पहले 256 बाइट्स को मैप करता है। आप ऑक्टेट-टू-स्ट्रिंग को हटा सकते हैं और वेक्टर हो सकते हैं।

यदि आप stderr भी चाहते थे, तो आप दोनों को प्राप्त करने के लिए नेस्टेड 'आउट-आउटपुट-टू-अनुक्रम' का उपयोग कर सकते हैं।

(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

मुझे आपके उदाहरण को चलाने में समस्याएं हैं I लिनक्स के तहत एसबीसीएल के साथ मुझे चेतावनी मिलती है: एनकोडिंग एक ज्ञात तर्क कीवर्ड नहीं है।, और चल रहा सुरक्षित-खोल मुझे "अज्ञात वर्ण एन्कोडिंग: # <बैबेल: बाहरी-प्रारूप आईएसओ -885 9 -1 एलएफ {1004CDC241}>" देता है। क्या मैं कुछ भूल रहा हूँ ? –

+0

एसबीसीएल और बेबेल के संस्करणों के बिना आप पूरी तरह से सुनिश्चित नहीं हैं। आप कोशिश कर सकते हैं: iso-8859-1 साथ ही, क्योंकि यह इसके लिए वैधानिक नाम है। सुनिश्चित करें कि OCTETS-TO-STRING बैबल से आ रहा है। –

+0

आह हाँ, मैं एसबी-एक्सटी का उपयोग कर रहा था: octects-to-string। सही कार्य और एसबीसीएल का सबसे हालिया संस्करण यह सही ढंग से काम करता प्रतीत होता है। बहुत धन्यवाद। –

2

पॉल नाथन पहले से ही के रूप में एक बहुत पूरा जवाब दे दी है कैसे आई/ओ बाइनरी के रूप में इस कार्यक्रम से पढ़ने के लिए, तो मैं बस जोड़ देंगे क्यों अपने कोड काम नहीं किया: क्योंकि आप का उपयोग करते हुए यूटीएफ -8 अक्षरों की एक स्ट्रिंग के रूप में I/O को समझने के लिए एसबीसीएल से स्पष्ट रूप से पूछा गया।

इसके अलावा, मैं यह इंगित करना चाहता हूं कि आपको समाधान प्राप्त करने के लिए run-program के स्रोत कोड तक जाने की आवश्यकता नहीं है। यह स्पष्ट रूप से SBCL's manual में प्रलेखित है।

+0

यह 'आउट-आउटपुट-टू-स्ट्रिंग' के लिए सच है (जो तत्व के प्रकार 'चरित्र' के रूप में है), लेकिन फ्लेक्सी-स्ट्रीम केस के लिए नहीं, जहां धारा octects से बना है। मुझे उम्मीद थी कि रन-प्रोग्राम धारा के आधार पर सही 'तत्व-प्रकार' के तत्वों को पढ़ेगा, लेकिन ऐसा लगता है कि ऐसा नहीं है। वैसे भी, मुझे अब एहसास है कि उदाहरण बहुत स्पष्ट नहीं हैं, मैं कुछ और विवरण अंत त्रुटि संदेश –

+0

डाल दूंगा लेकिन आप ध्यान दें कि आपको flexi-streams के साथ एक ही त्रुटि नहीं मिलती है। यदि आप त्रुटि संदेश और स्टैक ट्रेस देखते हैं, तो आप देखेंगे कि एक उचित अनुमान यह है कि एसबीसीएल किसी भी लेखन समारोह का उपयोग नहीं करता है लेकिन कुछ कार्यान्वयन-विशिष्ट अनुकूलन, और यह flexi-stream के साथ विफल रहता है। –