2013-06-29 13 views
5

Dato un flusso di input, vorrei creare una sequenza lenta dei dati sotto forma di array di byte (blocchi). Ecco la mia prova:Clojure: creazione di una sequenza lazy di blocchi di byte da un flusso di input

(defn- read-or-nil [stream] 
    (let [buf (byte-array 2)] 
    (when-not (= -1 (.read stream buf)) 
     buf))) 

(defn byte-chunk-seq [stream] 
    (cons (read-or-nil stream) (lazy-seq (byte-chunk-seq stream)))) 

(with-open [rdr (java.io.FileInputStream. "/tmp/wut")]                                               
    (take 2 (byte-chunk-seq rdr))) 

Nell'ultima dichiarazione, in cui sto testando il codice, ottengo un:

IOException flusso chiusa java.io.FileInputStream.readBytes (FileInputStream.java:-2).

Se cambio l'istruzione come take 1, restituisce correttamente, ma ciò non mi aiuta molto. Qualcuno ha qualche idea del perché questo non avrebbe funzionato?

risposta

4

Ci sono un paio di problemi.

In primo luogo, la sequenza lenta non è completamente corretta. L'intero corpo della funzione dovrebbe essere racchiuso in lazy-seq e dovrebbe passare in uno dei contro per continuare la sequenza, o zero per terminarlo.

(defn byte-chunk-seq [stream] 
    (lazy-seq (if-let [buf (read-or-nil stream)] 
       (cons buf (byte-chunk-seq stream)) 
       nil))) 

Secondo, take è anche pigro. Quindi la sequenza pigra non si realizzerà fino a dopo che with-open ha chiuso il flusso. È possibile evitare questo errore avvolgendo un doall attorno alla sequenza lazy per realizzarlo prima che lo streaming venga chiuso.

(with-open [rdr (java.io.FileInputStream. "/tmp/wut")] 
    (doall (take 2 (byte-chunk-seq rdr))))