Program Style for Rust

ファイルリストの順に、ネットから複数のファイルをダウンロードして保存する。
ファイルリスト順にネットからHTTPで複数のファイルを自動的にダウンロードして保存
ファイルリスト順にネットから複数のファイルを自動ダウンロード
ファイルリストを読み込んで、ネットから複数のファイルを自動的にダウンロードして保存する。

※Rust勉強中のため、プログラムが最適かどうかは不明です・・・。特にエラー処理の作法については試行錯誤中です。より良い書き方があれば、そちらを参考にしてください。

CODE

use std::fs::File;
use std::io::{Write};
use std::io::{BufRead, BufReader};

#[tokio::main]
async fn main() -> Result<(), Box> {

    let max_download_num=10;
    let file_name="download.csv";
    let sep="\t";

    let mut data_from;
    let mut file_to;
    
    let mut no:i32=0;
    let mut li:i32=0;
    for result in BufReader::new(File::open(file_name)?).lines() {
        if li>=max_download_num {
            break;
        }
        li=li+1;
        let line:String = result?;
        let v: Vec<&str> = line.split(sep).collect();
        if v.len()<2 {
            println!("Line No.{} skipped.", li);
            continue;
        }
        data_from=v[0];
        file_to=v[1];

        let resp=reqwest::get(data_from).await;
        if let Err(e) = resp {
            println!("Line No.{} Access Error : URL={} ",li,data_from);
            if e.is_redirect() {
                if let Some(final_stop) = e.url() {
                    println!("redirect loop at {}", final_stop);
                }
            }
            else if e.is_timeout() {
                println!("time out");
            }
            else if e.is_status() {
                let code=e.status();
                println!("status code = {}",code.unwrap());
            }
            else{
                println!("Unknown Error");
            }
            continue;
        }
        
        let _data=resp.unwrap().bytes().await;
        if let Err(_) = _data {
            continue;
        }
        let _buf = _data.unwrap();

        no=no+1;

        println!("{} Received... {}",no,data_from);

        let fresp = File::create(file_to);
        if let Err(_) = fresp {
            println!("Line No.{} File create Error(No.{} was received but canceled.)...{}",li,no,file_to);
            no = no-1;
            continue;
        }
        let mut file = fresp.unwrap();

        file.write_all(&_buf)?;
        file.flush()?;
    
        println!("{} Written ... {}",no,file_to);

    }

    println!("Done. {} line(s) processed, {} file(s) downloaded.",li,no);

    Ok(())
}

download.csvの例は以下の通り。

  • 1行に1データを記述。
  • 1データは、URL+TAB+ファイル名(ただし、TABはセパレータ)。URLからダウンロードしてきて、ファイル名に保存する。
  • セパレータ(初期値はTAB)を変更したい場合には、プログラムのSEPを書き換える。
  • 最大ダウンロード数(初期値は10)を変更したい場合にはmax_download_numを書き換える。
  • セパレータで分割した領域数が2未満の場合にはその行をskipします。
  • セパレータで分割した領域数が2以上の場合には、最初の2領域をURL,ファイル名として使います。
  • URLでアクセスエラーが出た場合、ファイルを書き込みできない場合には、skipします。
  • 最終的に処理した行数、ダウンロードした件数を表示します。

https://example.com/test.pdf	test.pdf
https://example2.net/picture.jpg	picture.jpg
http://example3.org/sample.png	sample.png

Cargo.toml には、以下を追加。

[dependencies]
reqwest = { version = "0.10" }
tokio = { version = "0.2", features = ["full"] }