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}