You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rust的for循环中读取文件行?实现C同款电影文件读取

在Rust中实现读取电影文件的功能

我已用C语言实现读取Movies.txt文件的功能,文件内每条电影条目包含name和rating两个属性。现需用Rust实现相同功能,以下是我的C语言代码、Rust尝试代码以及文件内容:

C语言实现代码

#include <cstdio>
#include <cstdlib>

void read_file() {
    FILE* movies = fopen("Movies.txt", "r");
    if (movies == nullptr) {
        perror("Error opening Movies.txt");
        exit(EXIT_FAILURE);
    }

    // contains only 4 entries as of now
    for (int i = 0; i < 4; ++i) {
        char name[1024]{};
        if (fscanf(movies, "%*[^=]=%s", name) == EOF) {
            perror("Error in reading Movies.txt");
            printf("in \"%s: %s\" at line %d\n", __FILE__, __func__, __LINE__);
            exit(EXIT_FAILURE);
        }

        float rating{};    
        if (fscanf(movies, "%*[^=]=%f", &rating) == EOF) {
            perror("Error in reading Movies.txt");
            printf("in \"%s: %s\" at line %d\n", __FILE__, __func__, __LINE__);
            exit(EXIT_FAILURE);
        }
        printf("Movie Name: %s\tRating: %f\n", name, rating);
    }

    fclose(movies);
}

int main() {
    read_file();
}

我的Rust尝试代码

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

fn read_file() {
    let file = File::open("Movies.txt");
    let buff_reader;
    match file {
        Ok(mut file) => buff_reader = BufReader::new(file),
        _err => return,
    }

    for (_, line) in buff_reader.lines().enumerate() {
        for i in [0..4] {
            let line = line.unwrap();
            let reg_ex = Regex::new(r"^[^=]+\s*=\s*(?<name>\w+)$").unwrap();
            let Some(caps) = reg_ex.captures(&line) else {
                println!("no match!");
                return;
            };
            
            // want to read next line... but how?
            // let line = line.unwrap();
            // let reg_ex = Regex::new(r"^[^=]+\s*=\s*(?<rating>\w+)$").unwrap();
            // let Some(caps) = reg_ex.captures(&line) else {
            //     println!("no match!");
            //     return;
            // };
            // println!("Movie Name: {}\tRating: {}", name, rating);
        }
    }
}

fn main() {
    read_file();
}

Movies.txt文件内容

Movie name: Harry Potter1
rating: 8.5
Movie name: Harry Potter2
rating: 9.5
Movie name: Harry Potter3
rating: 8
Movie name: Harry Potter4
rating: 8

Rust正确实现方案

不需要嵌套循环,直接通过迭代器每次读取两行(对应一个电影的名字和评分)即可。以下是更简洁且鲁棒的实现:

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

fn read_file() -> Result<(), Error> {
    // 打开文件,失败则返回错误
    let file = File::open("Movies.txt")?;
    let reader = BufReader::new(file);
    // 将行转换为迭代器
    let mut lines = reader.lines();

    // 每次读取两行:名字行 + 评分行
    while let (Some(name_line_res), Some(rating_line_res)) = (lines.next(), lines.next()) {
        // 处理行读取错误
        let name_line = name_line_res?;
        let rating_line = rating_line_res?;

        // 提取电影名:去除前缀"Movie name: "
        let name = name_line.strip_prefix("Movie name: ").ok_or_else(|| {
            Error::new(std::io::ErrorKind::InvalidData, "格式错误:无法解析电影名称行")
        })?;

        // 提取评分:去除前缀"rating: "并转换为浮点数
        let rating_str = rating_line.strip_prefix("rating: ").ok_or_else(|| {
            Error::new(std::io::ErrorKind::InvalidData, "格式错误:无法解析评分行")
        })?;
        let rating: f32 = rating_str.parse()?;

        // 输出结果
        println!("Movie Name: {}\tRating: {}", name, rating);
    }

    Ok(())
}

fn main() {
    // 统一处理所有错误
    if let Err(e) = read_file() {
        eprintln!("读取文件出错:{}", e);
    }
}

关键说明

  1. 迭代器读取两行:通过lines.next()连续调用两次,每次获取一个电影的名字行和评分行,无需硬编码循环次数(比如C语言中的4次),自动处理到文件结束。
  2. 简单解析方式:利用strip_prefix直接去除固定前缀,比正则表达式更高效且易维护。
  3. 完善的错误处理:使用?传播错误,在main函数中统一捕获并输出错误信息,避免直接unwrap导致程序崩溃。
  4. 类型安全:将评分字符串转换为f32类型,确保类型正确性。

如果一定要使用正则表达式,也可以修改解析部分,比如:

// 需要在Cargo.toml中添加依赖:regex = "1.10", lazy_static = "1.4"
use regex::Regex;
use lazy_static::lazy_static;

// 预编译正则表达式,避免重复编译开销
lazy_static! {
    static ref NAME_REGEX: Regex = Regex::new(r"^Movie name: (?P<name>.+)$").unwrap();
    static ref RATING_REGEX: Regex = Regex::new(r"^rating: (?P<rating>\d+(\.\d+)?)$").unwrap();
}

// 在read_file函数内替换解析部分
let name = NAME_REGEX.captures(&name_line)
    .and_then(|caps| caps.name("name"))
    .map(|m| m.as_str())
    .ok_or_else(|| Error::new(std::io::ErrorKind::InvalidData, "格式错误:无法解析电影名称行"))?;

let rating = RATING_REGEX.captures(&rating_line)
    .and_then(|caps| caps.name("rating"))
    .map(|m| m.as_str().parse::<f32>())
    .ok_or_else(|| Error::new(std::io::ErrorKind::InvalidData, "格式错误:无法解析评分行"))??;

内容的提问来源于stack exchange,提问作者Harry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 04:37:13