seqio/
utils.rs

1//! # File io utils
2//! * [`file_reader`] open uncompressed/gzipped file from `std::io::stdin` or file
3//! * [`file_writer`] write uncompressed/gzipped content to `std::io::stdout` or file
4//! * [`file_writer_append`] append uncompressed/gzipped content to file
5//!
6//! # Example
7//! The following example shows how to use.
8//!
9//! ### read: [`file_reader`]
10//! ```rust ignore
11//! use std::io::BufRead;
12//! use seqio::utils::file_reader;
13//!
14//! let file: &Option<&str> = &Some("path_to_file"); // for uncompressed file
15//! let file: &Option<&str> = &Some("path_to_file.gz"); // for gzipped compressed file
16//! let file: &Option<&str> = &None; // read from std::io::stdin
17//!
18//! let fp = file_reader(file)?;
19//!
20//! for line in fp.lines().flatten() {
21//!     println!("{}",line);
22//!     todo!();
23//! }
24//! ```
25//!
26//!
27//! ### write: [`file_writer`]
28//!
29//! ```rust ignore
30//! use std::io::BufRead;
31//! use seqio::utils::file_writer;
32//!
33//! let output: &Option<&str> = &Some("write_file_name"); // output uncompressed file
34//! let output: &Option<&str> = &Some("write_file_name.gz"); // output gzipped compressed file
35//! let output: &Option<&str> = &None; //  write to std::io::stdout
36//!
37//! let mut fo = file_writer(output)?;
38//! fo.write(b"foo\nbar")?;
39//! fo.flush()?;
40//! ```
41//!
42//!
43//! ### append: [`file_writer_append`]
44//! ```rust ignore
45//! use std::io::BufRead;
46//! use seqio::utils::file_writer_appned;
47//!
48//! let append: &str = "newfile";
49//! let append: &str = "append_file.gz";
50//!
51//! let mut fo_append = file_writer_append(append)?;
52//!
53//! fo_append.write(b"line one")?;
54//! fo_append.write(b"line two")?;
55//! fo.flush()?
56//! ```
57//! Automatically create new files if file is not exists
58use flate2::{read, write, Compression};
59/// date 2023.11.23
60use std::{
61    fs::{File, OpenOptions},
62    io::{self, prelude::*, BufRead, BufReader, BufWriter, Result, Write},
63};
64
65/// gzipped file magic number
66pub const GZ_MAGIC: [u8; 3] = [0x1f, 0x8b, 0x08];
67
68/// io buffer size
69pub const BUFF_SIZE: usize = 1024 * 1024;
70
71/// file is gzipped or not
72pub fn is_gzipped(file_name: &str) -> Result<bool> {
73    let mut buffer: [u8; 3] = [0; 3];
74    let mut fp = File::open(file_name)?;
75    let _x = fp.read(&mut buffer)?;
76    Ok(buffer == GZ_MAGIC || file_name.ends_with(".gz"))
77}
78
79/// open a file reader and return a iterator
80#[rustfmt::skip]
81pub fn file_reader(file_in: &Option<&str>) -> Result<Box<dyn BufRead>> {
82    if let Some(file_name) = file_in {
83        let fp = File::open(file_name)?;
84        let flag = is_gzipped(file_name)?;
85
86        if flag {
87            Ok(Box::new(BufReader::with_capacity(
88                BUFF_SIZE,
89                read::MultiGzDecoder::new(fp),
90            )))
91        } else {
92            Ok(Box::new(BufReader::with_capacity(BUFF_SIZE, fp)))
93        }
94    } else {
95        let fp = BufReader::new(io::stdin());
96        Ok(Box::new(fp))
97    }
98}
99
100/// open a file and return a file writer
101#[rustfmt::skip]
102pub fn file_writer(file_out: &Option<&str>) -> Result<Box<dyn Write>> {
103    if let Some(file_name) = file_out {
104        let fp = File::create(file_name)?;
105
106        if file_name.ends_with(".gz") || file_name.ends_with(".gzip") {
107            Ok(Box::new(BufWriter::with_capacity(
108                BUFF_SIZE,
109                write::GzEncoder::new(fp, Compression::default()),
110            )))
111        } else {
112            Ok(Box::new(BufWriter::with_capacity(BUFF_SIZE, fp)))
113        }
114    } else {
115        Ok(Box::new(BufWriter::new(io::stdout())))
116    }
117}
118
119/// open a file and return a file writer with append model
120#[rustfmt::skip]
121pub fn file_writer_append(file_out: &str) -> Result<Box<dyn Write>> {
122    let fp = OpenOptions::new()
123        .append(true)
124        .create(true)
125        .open(file_out)?;
126    
127    if file_out.ends_with(".gz") || file_out.ends_with(".gzip") {
128        Ok(Box::new(BufWriter::with_capacity(
129            BUFF_SIZE,
130            write::GzEncoder::new(fp, Compression::default()),
131        )))
132    } else {
133        Ok(Box::new(BufWriter::with_capacity(BUFF_SIZE, fp)))    
134    }
135}