Writer of BAM file format. | (ns cljam.io.bam.writer (:require [clojure.java.io :as cio] [cljam.io.protocols :as protocols] [cljam.io.sam.util.refs :as refs] [cljam.io.sam.util.header :as header] [cljam.io.util.lsb.io-stream :as lsb] [cljam.io.bam.common :as common] [cljam.io.bam.encoder :as encoder] [cljam.io.bam.decoder :as bam-decoder] [cljam.io.bam-index.writer :as bai-writer]) (:import [java.io ByteArrayOutputStream Closeable DataOutputStream] [cljam.io.bam.decoder BAMRawBlock] [bgzf4j BGZFOutputStream])) |
(declare write-header* write-refs* write-alignments* write-blocks*) | |
Returns true if the bam is sorted by coordinate, false if not.
It is detected by | (defn- sort-by-pos? [header] (let [so (:SO (:HD header))] (= so (name :coordinate)))) |
BAMWriter | |
(deftype BAMWriter [url writer data-writer refs index] Closeable (close [this] (.close ^Closeable (.data-writer this)) (when-let [idx @index] (let [last-pointer (.getFilePointer ^BGZFOutputStream writer) n-refs (count @refs)] (with-open [w (->> (str url ".bai") cio/output-stream DataOutputStream.)] (->> (bai-writer/update-last-pointer idx last-pointer) (bai-writer/finalize-index n-refs) (bai-writer/write-index*! w n-refs)))))) protocols/IWriter (writer-url [this] (.url this)) protocols/IAlignmentWriter (write-header [this header] (write-header* this header)) (write-refs [this header] (write-refs* this header)) (write-alignments [this alignments header] (write-alignments* this alignments header)) (write-blocks [this blocks] (write-blocks* this blocks))) | |
write | |
(defn- write-header* [^BAMWriter wtr header] (swap! (.index wtr) #(and (sort-by-pos? header) %)) (let [w (.data-writer wtr) header-string (str (header/stringify-header header) \newline)] (lsb/write-bytes w (.getBytes ^String common/bam-magic)) ; magic (lsb/write-int w (count header-string)) (lsb/write-string w header-string))) | |
(defn- write-refs* [^BAMWriter wtr header] (let [w (.data-writer wtr) refs (refs/make-refs header)] (when @(.index wtr) (reset! (.refs wtr) refs)) (lsb/write-int w (count refs)) (doseq [{:keys [len] name' :name} refs] (lsb/write-int w (inc (count name'))) (lsb/write-string w name') (lsb/write-bytes w (byte-array 1 (byte 0))) (lsb/write-int w len)))) | |
(defn- write-alignments* [^BAMWriter wtr alns header] (let [dw (.data-writer wtr) w ^BGZFOutputStream (.writer wtr) refs (refs/make-refs header)] (with-open [baos (ByteArrayOutputStream. 4096) dos (DataOutputStream. baos)] (let [pointer-block (map (fn [a] (let [pointer-beg (.getFilePointer w)] (.reset baos) (encoder/encode-alignment dos a refs) (lsb/write-int dw (.size baos)) (.writeTo baos dw) (when @(.index wtr) (bam-decoder/decode-pointer-block (BAMRawBlock. (.toByteArray baos) pointer-beg (.getFilePointer w)))))) alns)] (if @(.index wtr) (reset! (.index wtr) (->> pointer-block bai-writer/make-index* (bai-writer/merge-index @(.index wtr)))) (dorun pointer-block)) nil)))) | |
(defn- write-blocks* [^BAMWriter wtr blocks] (let [dw (.data-writer wtr) w ^BGZFOutputStream (.writer wtr) pointer-block (map (fn [{:keys [data]}] (let [pointer-beg (.getFilePointer w)] (lsb/write-int dw (alength ^bytes data)) (lsb/write-bytes dw data) (when @(.index wtr) (bam-decoder/decode-pointer-block (BAMRawBlock. data pointer-beg (.getFilePointer w)))))) blocks)] (if @(.index wtr) (reset! (.index wtr) (->> pointer-block bai-writer/make-index* (bai-writer/merge-index @(.index wtr)))) (dorun pointer-block)) nil)) | |