Rust基因组数据处理库rust-htslib的使用:支持SAM/BAM/CRAM/VCF/BCF等格式的高效读写与操作

Rust基因组数据处理库rust-htslib的使用:支持SAM/BAM/CRAM/VCF/BCF等格式的高效读写与操作

简介

rust-htslib是一个提供HTSlib绑定和高级Rust API的库,用于读写BAM文件。它支持多种基因组数据格式包括SAM、BAM、CRAM、VCF和BCF等。

安装

在Cargo.toml中添加以下依赖:

[dependencies]
rust-htslib = "*"

或者运行以下命令:

cargo add rust-htslib

功能选项

默认情况下,rust-htslib链接到bzip2-syslzma-sys以支持完整的CRAM功能。如果不需要CRAM支持,可以禁用这些功能:

[dependencies]
rust-htslib = { version = "*", default-features = false }

其他可选功能:

  • serde:支持bam::Record的序列化/反序列化
  • curl:HTTP文件访问支持
  • s3gcs:S3和Google Cloud Storage支持(测试版)
  • bindgen:为htslib生成绑定(会显著增加构建时间)

完整示例

以下是一个使用rust-htslib读取BAM文件的完整示例:

use rust_htslib::{bam, bam::Read};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 打开BAM文件
    let mut bam = bam::Reader::from_path("input.bam")?;
    
    // 创建BAM头信息
    let header = bam::Header::from_template(bam.header());
    
    // 创建输出BAM文件
    let mut out = bam::Writer::from_path("output.bam", &header, bam::Format::Bam)?;
    
    // 遍历所有记录
    for result in bam.records() {
        let mut record = result?;
        
        // 在这里处理每条记录
        // 例如:过滤质量值大于20的记录
        if record.mapq() > 20 {
            out.write(&record)?;
        }
    }
    
    Ok(())
}

另一个示例,展示如何读取VCF文件:

use rust_htslib::{vcf, vcf::Read};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 打开VCF文件
    let mut vcf = vcf::Reader::from_path("input.vcf")?;
    
    // 创建输出VCF文件
    let header = vcf::Header::from_template(vcf.header());
    let mut out = vcf::Writer::从路径("output.vcf", &header, false)?;
    
    // 遍历所有变异记录
    for result in vcf.records() {
        let record = result?;
        
        // 在这里处理每条变异记录
        // 例如:过滤PASS的变异
        if record.is_pass() {
            out.write(&record)?;
        }
    }
    
    Ok(())
}

替代方案

noodles是另一个由Michael Macias实现的纯Rust方案,实现了htslib的大部分C功能(仍处于实验阶段)。

作者

  • Johannes Köster
  • Christopher Schröder
  • Patrick Marks
  • David Lähnemann
  • Manuel Holtgrewe
  • Julian Gehring

许可证

MIT许可证

更多完整示例

示例1:BAM文件索引查询

use rust_htslib::{bam, bam::IndexedReader};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 创建索引读取器
    let mut bam = bam::IndexedReader::from_path("input.bam")?;
    
    // 查询特定区域
    let tid = 0; // 染色体ID
    let start = 10000; // 起始位置
    let end = 20000; // 结束位置
    
    // 获取区域内的记录
    for record in bam.query(tid, start, end)? {
        let record = record?;
        println!("Found record at {}", record.pos());
    }
    
    Ok(())
}

示例2:BCF文件写入

use rust_htslib::bcf::{self, Read, Writer, Format};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 读取BCF文件
    let mut bcf = bcf::Reader::from_path("input.bcf")?;
    
    // 创建输出BCF文件
    let header = bcf::Header::from_template(bcf.header());
    let mut out = bcf::Writer::from_path("output.bcf", &header, false, Format::BCF)?;
    
    // 遍历记录并写入
    for result in bcf.records() {
        let record = result?;
        out.write(&record)?;
    }
    
    Ok(())
}

示例3:SAM文件转换

use rust_htslib::{sam, bam};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 读取SAM文件
    let mut sam = sam::Reader::from_path("input.sam")?;
    
    // 创建BAM输出文件
    let header = bam::Header::from_template(sam.header());
    let mut bam = bam::Writer::from_path("output.bam", &header, bam::Format::Bam)?;
    
    // 转换记录
    for record in sam.records() {
        let record = record?;
        bam.write(&record.to_bam())?;
    }
    
    Ok(())
}

1 回复

Rust基因组数据处理库rust-htslib的使用指南

概述

rust-htslib是Rust语言对HTSlib(C库)的绑定,提供了高效处理基因组数据的接口,支持多种常见生物信息学文件格式:

  • 序列比对格式:SAM/BAM/CRAM
  • 变异数据格式:VCF/BCF
  • 索引格式:CSI/BAI/TBI

安装方法

在Cargo.toml中添加依赖:

[dependencies]
htslib = "0.40"

核心功能与使用示例

1. BAM文件读取

use htslib::{bam, bam::Read};

fn read_bam_file(path: &str) -> Result<(), Box<dyn std::error::Error>> {
    // 打开BAM文件
    let mut bam = bam::Reader::from_path(path)?;
    
    // 遍历所有记录
    for record in bam.records() {
        let record = record?;
        println!("Read {} at position {}:{}", 
            bam::record::Record::qname(&record),
            record.tid(),
            record.pos());
    }
    
    Ok(())
}

2. BAM文件写入

use htslib::{bam, bam::Write};

fn write Bam文件写入

```rust
use htslib::{bam, bam::Write};

fn write_bam_file(input: &str, output: &str) -> Result<(), Box<dyn std::error::Error>> {
    // 读取输入文件
    let mut in_bam = bam::Reader::from_path(input)?;
    
    // 创建输出文件
    let header = bam::Header::from_template(in_bam.header());
    let mut out_bam = bam::Writer::from_path(output, &header, bam::Format::Bam)?;
    
    // 复制记录
    for record in in_bam.records() {
        out_bam.write(&record?)?;
    }
    
    Ok(())
}

3. VCF文件处理

use htslib::{vcf, vcf::Read};

fn process_vcf(path: &str) -> Result<(), Box<dyn std::error::Error>> {
    // 打开VCF文件
    let mut vcf = vcf::Reader::from_path path)?;
    
    // 读取头信息
    let header = vcf.header().clone();
    
    // 遍历变异记录
    for record in vcf.records() {
        let record = record?;
        println!("Variant at {}:{}", record.chrom(), record.pos());
        
        // 获取基因型信息
        if let Some(gt) = record.genotypes() {
            for sample in gt.iter() {
                println!("Sample genotype: {:?}", sample);
            }
        }
    }
    
    Ok(())
}

4. 使用索引进行区域查询

use htslib::{bam, bam::IndexedReader};

fn query_region(bam_path: &str, region: &str) -> Result<(), Box<dyn std::error::Error>> {
    // 创建带索引的读取器
    let mut bam = bam::IndexedReader::from_path(bam_path)?;
    
    // 解析区域字符串
    let (tid, start, end) = bam.parse_region(region)?;
    
    // 查询特定区域
    bam.fetch((tid, start, end))?;
    
    // 遍历区域内的记录
    for record in bam.records() {
        let record = record?;
        println!("Read in region: {}", bam::record::Record::qname(&record));
    }
    
    Ok(())
}

高级特性

多线程处理

use htslib::bam;
use rayon::prelude::*;

fn parallel_process(bam_path: &str) -> Result<(), Box<dyn std::error::Error>> {
    let bam = bam::IndexedReader::from_path(bam_path)?;
    
    // 收集所有记录(注意内存使用)
    let records: Vec<_> = bam.records().collect::<Result<Vec<_>, _>>()?;
    
    // 并行处理
    records.par_iter().for_each(|record| {
        // 处理每条记录
        let _length = record.seq().len();
        // 其他处理...
    });
    
    Ok(())
}

自定义记录过滤

use htslib::bam;

fn filter_records(bam_path: &str, min_qual: u8) -> Result<(), Box<dyn std::error::Error>> {
    let mut bam = bam::Reader::from_path(bam_path)?;
    
    for record in bam.records() {
        let record = record?;
        
        // 过滤低质量记录
        if record.mapq() >= min_qual {
            println!("High quality read: {}", bam::record::Record::qname(&record));
        }
    }
    
    Ok(())
}

性能提示

  1. 使用IndexedReader进行区域查询比全文件扫描快得多
  2. 批量处理记录比逐条处理更高效
  3. 对于大型文件,考虑使用多线程处理
  4. 避免频繁的内存分配,重用记录对象

错误处理

rust-htslib使用Rust的标准错误处理机制,建议使用?操作符或match表达式处理可能的错误:

match bam::Reader::from_path("input.bam") {
    Ok(reader) => {
        // 处理文件
    },
    Err(e) => {
        eprintln!("Failed to open BAM file: {}", e);
        // 错误处理
    }
}

完整示例

下面是一个完整的示例,展示如何使用rust-htslib从BAM文件中读取数据并进行简单分析:

use htslib::{bam, bam::Read};

fn analyze_bam(bam_path: &str) -> Result<(), Box<dyn std::error::Error>> {
    // 打开BAM文件
    let mut bam = bam::Reader::from_path(bam_path)?;
    
    // 获取参考序列信息
    let header = bam.header();
    let targets = header.target_names();
    println!("Reference sequences: {:?}", targets);
    
    // 统计读取数和映射质量
    let mut total_reads = 0;
    let mut mapped_reads = 0;
    let mut total_mapq = 0;
    
    for record in bam.records() {
        let record = record?;
        total_reads += 1;
        
        // 检查是否映射
        if !record.is_unmapped() {
            mapped_reads += 1;
            total_mapq += record.mapq() as usize;
        }
    }
    
    // 计算结果
    let mapping_rate = mapped_reads as f64 / total_reads as f64 * 100.0;
    let avg_mapq = if mapped_reads > 0 {
        total_mapq as f64 / mapped_reads as f64
    } else {
        0.0
    };
    
    println!("Total reads: {}", total_reads);
    println!("Mapped reads: {}", mapped_reads);
    println!("Mapping rate: {:.2}%", mapping_rate);
    println!("Average mapping quality: {:.2}", avg_mapq);
    
    Ok(())
}

fn main() {
    if let Err(e) = analyze_bam("example.bam") {
        eprintln!("Error analyzing BAM file: {}", e);
    }
}

总结

rust-htslib提供了高性能的基因组数据处理能力,结合Rust的安全性和并发特性,非常适合构建高效、可靠的生物信息学分析工具。通过合理使用其API,可以处理大规模基因组数据,同时保证代码的安全性和性能。

回到顶部