毛华枝 發表於 2024-5-28 09:50:59

Rust使用csv crate构建CSV文件读取器的全过程

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>效果演示</li><li>快速上手</li><li>命令行程序封装</li><li>总结</li></ul></div><p class="maodian"></p><h2>效果演示</h2>
<p style="text-align:center"><img alt="csv" src="https://img.jbzj.com/file_images/article/202405/202405280945348.gif" /></p>
<p class="maodian"></p><h2>快速上手</h2>
<p>依赖导入:</p>
<div class="jb51code"><pre class="brush:bash;">cargo add csv</pre></div>
<p>读取实现:</p>
<div class="jb51code"><pre class="brush:plain;">use std::error::Error;
use std::fs::File;
use std::path::Path;

fn read_csv&lt;P: AsRef&lt;Path&gt;&gt;(filename: P) -&gt; Result&lt;(), Box&lt;dyn Error&gt;&gt; {
    let file = File::open(filename)?;
    let mut rdr = csv::Reader::from_reader(file);

    for result in rdr.records() {
      let record = result?;
      println!("{:?}", record);
    }

    Ok(())
}

fn main() -&gt; Result&lt;(), Box&lt;dyn Error&gt;&gt; {
    let filename = "src/email.csv";
    read_csv(filename)
}
</pre></div>
<blockquote><p>这是一段简单的<code>Rust</code>程序,演示了如何使用<code>csv``crate</code>中的读取<code>API</code>,通过指定<code>csv</code>路径进行<code>csv</code>数据的读取。</p></blockquote>
<ul><li><code>use std::error::Error;</code>, <code>use std::fs::File;</code>, <code>use std::path::Path;</code>:
<ul><li>这些是Rust语言中用于导入标准库中的错误处理、文件操作和路径相关模块的语句。</li></ul></li><li><code>fn read_csv&lt;P: AsRef&lt;Path&gt;&gt;(filename: P) -&gt; Result&lt;(), Box&lt;dyn Error&gt;&gt;</code>:<ul><li>这是一个函数定义,名为<code>read_csv</code>,它接受一个实现了<code>AsRef&lt;Path&gt;</code>&nbsp;trait 的泛型参数<code>P</code>,表示文件名。函数返回一个<code>Result</code>枚举类型,其中<code>Ok(())</code>表示成功,<code>Err</code>包含一个实现了<code>Error</code>&nbsp;trait 的错误对象的<code>Box</code>指针。</li><li>函数打开指定的CSV文件,创建一个CSV读取器(<code>csv::Reader</code>),然后遍历文件中的每一行记录并打印出来。</li></ul></li><li><code>fn main() -&gt; Result&lt;(), Box&lt;dyn Error&gt;&gt;</code>:<ul><li>这是程序的入口点,也是主函数。它也返回一个<code>Result</code>枚举类型,用于处理可能出现的错误。</li><li>在<code>main</code>函数中,指定了要读取的CSV文件的文件名为<code>&quot;src/email.csv&quot;</code>,然后调用<code>read_csv</code>函数来处理这个文件。</li></ul></li><li><code>let file = File::open(filename)?;</code>:<ul><li>在<code>read_csv</code>函数中,这行代码尝试打开指定的文件,<code>?</code>操作符用于处理可能出现的错误,如果出现错误,则会将错误传播到调用方。</li></ul></li><li><code>let mut rdr = csv::Reader::from_reader(file);</code>:<ul><li>创建一个CSV读取器<code>rdr</code>,并从打开的文件中读取数据。</li></ul></li><li><code>for result in rdr.records() { ... }</code>:<ul><li>使用<code>for</code>循环遍历CSV文件中的每一行记录。</li></ul></li><li><code>let record = result?;</code>:<ul><li>在循环中,尝试将每一行记录解析为<code>csv::StringRecord</code>类型的<code>record</code>,<code>?</code>操作符用于处理可能的解析错误。</li></ul></li><li><code>println!(&quot;{:?}&quot;, record);</code>:<ul><li>打印每一行记录的内容。</li></ul></li><li><code>Ok(())</code>:<ul><li>在函数末尾,返回一个<code>Ok(())</code>表示函数执行成功。</li></ul></li></ul>
<p>读取结果:</p>
<p style="text-align:center"><img alt="image-20240526192615414" src="https://img.jbzj.com/file_images/article/202405/202405280945349.png" /></p>
<p><code>csv</code>文件的读取功能基本实现了,但是每次读取需要我们手动修改代码,指定要读取的<code>csv</code>文件路径,相对还是不够实用和灵活,特别是对于非程序猿来说。下面将对代码进行进一步提取和优化,将读取的功能封装为命令行程序,提升使用体验。</p>
<p class="maodian"></p><h2>命令行程序封装</h2>
<p>关于命令行,<code>Rust</code>的<code>crate</code>中有很多不错的库,在之前我的文章中也提及了部分,这里选择使用<code>clap</code>这个<code>crate</code>来实现。</p>
<div class="jb51code"><pre class="brush:plain;">
ansi_term = "0.12.1"
clap = { version = "4.5.4", features = ["derive"] }
csv = "1.3.0"
prettytable-rs = "0.10.0"
</pre></div>
<p>结构分离,为了利于维护,将读取<code>CSV</code>文件的方法独立在<code>lib.rs</code>中,命令行参数处理等内容依旧在<code>main.rs</code></p>
<p>lib.rs</p>
<div class="jb51code"><pre class="brush:plain;">pub fn read_csv&lt;P: AsRef&lt;Path&gt;&gt;(filename: P) -&gt; Result&lt;(), Box&lt;dyn Error&gt;&gt; {
    let file = File::open(filename)?;
    let mut rdr = csv::Reader::from_reader(file);

    let mut table = Table::new();

    // 添加表头
    let headers = rdr
      .headers()?
      .iter()
      .map(|h| Cell::new(h).style_spec("Fg=green"))
      .collect();
    table.add_row(Row::new(headers));

    // 添加记录
    for result in rdr.records() {
      let record = result?;
      let cells: Vec&lt;Cell&gt; = record.iter().map(|field| Cell::new(field)).collect();
      table.add_row(Row::new(cells));
    }

    table.printstd();
    Ok(())
}
</pre></div>
<blockquote><p>感觉没啥新的东西可以讲的,这个方法的主要逻辑在上面已经说过,至于内容的打印,还是使用之前在X-SCAN端口扫描器中使用的Table进行美化。</p></blockquote>
<p>main.rs</p>
<div class="jb51code"><pre class="brush:plain;">use x_csvreader::read_csv;
#
struct Args {
    #
    path: String,
}
fn print_infos() {
    println!(
      "{}",
      Blue.paint(
            r#"
            __   __      ____________      __   _____                _
            \ \ / /   / ____|/ ____\ \    / /    |__ \            | |
             \ V /_____| |    | (___\ \/ /_____| |__) |_____ ___| | ___ _ __
            &gt; &lt;______| |   \___ \\ \/ /______|_// _ \/ _` |/ _` |/ _ \ '__|
             / . \   | |____ ____) |\/       | | \ \__/ (_| | (_| |__/ |
            /_/ \_\   \_____|_____/    \/      |_|\_\___|\__,_|\__,_|\___|_|
      author:代号0408
      version:0.1.0
      "#
      )
    );
}
fn main() {
    print_infos();
    let args = Args::parse();
    // 调用lib.rs中定义的read_csv函数
    match read_csv(&amp;args.path) {
      Ok(_) =&gt; {
            println!("=============================");
            println!("CSV 文件读取成功!");
      }
      Err(e) =&gt; {
            eprintln!("读取 CSV 文件时出现错误:{}", e);
      }
    }
}
</pre></div>
<blockquote><p>逻辑简单,就不赘述了。如果不了解字符打印美化和表格美化这两个<code>lib</code>基本使用的,建议翻下我往期的文章,都是有写的。</p></blockquote>
<p>那么如何使用呢?</p>
<div class="jb51code"><pre class="brush:bash;">cargo run -- --path &lt;csv文件路径&gt;
</pre></div>
<p>不妨将开头的效果复现一下:</p>
<div class="jb51code"><pre class="brush:bash;">cargo run -- --path C:\RustProjects\x-csvreader\src\email.csv</pre></div>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202405/2024052809453410.png" /></p>
<p>当然,为了演示的效果,这里选择的<code>CSV</code>文件数据量并不大,处理大数据量的文件也是可以的,只不过打印出来的表格数据可能会出现终端 <strong>霸屏</strong>的情况,纸上得来终觉浅!建议你自己试试,这里就不截图了。</p>
<p class="maodian"></p><h2>总结</h2>
<p>这篇文章主要学习如何基于<code>Rust</code>使用<code>csv</code>这个<code>crate</code>构建一个<code>CSV</code>文件读取器的过程。学习了<code>csv</code>相关的用法以及一些往期学过的<code>crate</code>的复习,兼顾了实用性和<code>Rust</code>的学习,是个很不错的练手小项目。</p>
<p>以上就是Rust使用csv crate构建CSV文件读取器的全过程的详细内容,更多关于Rust CSV文件读取器的资料请关注琼殿技术社区其它相关文章!</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>Rust初体验:手把手教你构建‘Hello, World!’</li><li>Rust实现构建器模式和如何使用Bon库中的构建器</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: Rust使用csv crate构建CSV文件读取器的全过程