Rustでfastq/fastq.gzを読み書きする
TL;DR
fastqとかのファイルを処理するときに、Pythonだとサイズが大きめのfastqファイル群を扱ってると時間がかかりすぎて辛い気分になります。fastqをパースするくらいなら自前で書いてもいいんですが、rust-bioなるcrateがあるのでそれを使います。
使い方はdocs読めばわかるんですが、gz形式で読み書きするのがrust-bio単独では使えなかったので、そのあたりもフォローしておきます。
dependencies
Cargo.toml
rust-bioのio::fastqに関する注意
rust-bioにはfastqパーサーがおいてあります。RecordがStringとかを持つ仕様なので、アロケーションの償却とかそういう意味だとちょっと速度は微妙な可能性があります。Errorハンドリングとかは参考になるので、高速化したいなら自分で書いたほうがいいかもしれません。
fastqの読み書き
Record
fastqの1 readに相当するRecordの定義は以下のようになっています。
それぞれのメンバは同名の関数(ex id())などでアクセスできます。ただ、seq()関数だけByteのスライスを返してきます。もうそれなら最初から全部&[u8]で読み込んでほしい...。
Reader
docsのほぼコピペを貼ります。
この場合、標準入力から読み出していますが、圧倒的多数であろうファイルから読み込みたい場合は、
でReaderを作成できます。
Write
docsのほぼコピペを再び貼ります。
Readerと同じで、ファイルに書き込みたい場合は、
を使います。
fastq.gzの読み書き
flate2というgzとかzipとかの圧縮を扱えるcrateを使います。?を使いたいので、anyhowというエラーハンドリングクレートを使用しています。
Cargo.toml
Read
fastq::Reader::newはtraitとしてstd::io::BufReadを持っている必要があります。
gzが拡張子についていれば、gzdecoderで読み込んで、そうでなければ普通にBufreadで読み込む関数を作成しておきます。decoderにはflate2のMultiGzDecoderを使用します。
これでgzからの読み込みの準備は整いました。あとは
のような形でReaderを生成できます。
Write
WriterもReaderと同じような感じでBufWriteを生成して、fastq::io::Writer::new()すればいいです。同じ用にラッパー関数を作ればよいですが、ちょっとこっちはgzで書き出さないメリットが思い浮かばないので、作ったことがないので、直接gzencoderを入れるコードをおいておきます。そのうち書くかもしれません。
まとめ
docsを読めばいいと思います。