读取文件并获取字符串数组 [英] Read a file and get an array of strings

查看:47
本文介绍了读取文件并获取字符串数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想读取一个文件并获取一个 String s的向量.以下功能有效,但是有没有更简洁或惯用的方式?

 使用std :: fs :: File;使用std :: io :: Read;fn lines_from_file(文件名:& str)->Vec< String>{让mut file =匹配File :: open(filename){Ok(文件)=>文件,Err(_)=>恐慌!(无此文件"),};让mut file_contents = String :: new();file.read_to_string(& mut file_contents).好的().expect(阅读失败!");让线:Vec< String>= file_contents.split("\ n").map(| s:& str | s.to_string()).搜集();线} 

一些对我而言不太理想的事情:

  • 用于读取文件的两次单独的错误检查.
  • 将整个文件读取为 String ,该文件将被丢弃.如果我只想要前N行,这将特别浪费.
  • 每行制作一个& str ,将其丢弃,而不是以某种方式直接从文件转到每行 String .

如何改进?

解决方案

DK.的答案是正确的,并且有很好的解释.但是,您说:

读取文件并获取字符串数组

Rust数组具有固定的长度,在编译时已知,因此我假设您的意思是向量".我会这样写:

 使用std :: {fs :: File,io :: {prelude :: *,BufReader},路径::路径};fn lines_from_file(文件名:impl AsRef< Path>)->Vec< String>{let file = File :: open(filename).expect(没有这样的文件");让buf = BufReader :: new(file);buf.lines().map(| l | l.expect(无法解析行")).搜集()}//-fn main(){let lines = lines_from_file("/etc/hosts");用于行中的行{println!("{:?}",行);}} 

  1. 在另一个答案中,使用对文件名实现 AsRef 的泛型类型是值得的.
  2. Result :: expect 缩短了 Err 的恐慌.
  3. BufRead :: lines 处理多种类型的换行符,而不仅仅是"\ n" .
  4. BufRead :: lines 还为您提供了单独分配的 String s,而不是一个大问题.
  5. 没有理由仅仅为了返回临时变量而将其收集到临时变量中.

    尤其没有理由重复类型( Vec< String> ).

如果要在失败时返回 Result ,则可以将实现压缩为一行:

 使用std :: {fs :: File,io :: {self,BufRead,BufReader},路径::路径};fn lines_from_file(文件名:impl AsRef< Path>)->io :: Result< Vec< String>>{BufReader :: new(File :: open(filename)?).lines().collect()}//-fn main(){let lines = lines_from_file("/etc/hosts").expect(无法加载行");用于行中的行{println!("{:?}",行);}} 

I want to read a file and get back a vector of Strings. The following function works, but is there a more concise or idiomatic way?

use std::fs::File;
use std::io::Read;

fn lines_from_file(filename: &str) -> Vec<String> {
    let mut file = match File::open(filename) {
        Ok(file) => file,
        Err(_) => panic!("no such file"),
    };
    let mut file_contents = String::new();
    file.read_to_string(&mut file_contents)
        .ok()
        .expect("failed to read!");
    let lines: Vec<String> = file_contents.split("\n")
        .map(|s: &str| s.to_string())
        .collect();
    lines
}

Some things that seem suboptimal to me:

  • Two separate error checks for reading the file.
  • Reading the entire file to a String, which will be thrown away. This would be particularly wasteful if I only wanted the first N lines.
  • Making a &str per line, which will be thrown away, instead of somehow going straight from the file to a String per line.

How can this be improved?

解决方案

DK.'s answer is quite right and has great explanation. However, you stated:

Read a file and get an array of strings

Rust arrays have a fixed length, known at compile time, so I assume you really mean "vector". I would write it like this:

use std::{
    fs::File,
    io::{prelude::*, BufReader},
    path::Path,
};

fn lines_from_file(filename: impl AsRef<Path>) -> Vec<String> {
    let file = File::open(filename).expect("no such file");
    let buf = BufReader::new(file);
    buf.lines()
        .map(|l| l.expect("Could not parse line"))
        .collect()
}

// ---

fn main() {
    let lines = lines_from_file("/etc/hosts");
    for line in lines {
        println!("{:?}", line);
    }
}

  1. As in the other answer, it's worth it to use a generic type that implements AsRef for the filename.
  2. Result::expect shortens the panic on Err.
  3. BufRead::lines handles multiple types of newlines, not just "\n".
  4. BufRead::lines also gives you separately allocated Strings, instead of one big glob.
  5. There's no reason to collect to a temporary variable just to return it. There's especially no reason to repeat the type (Vec<String>).

If you wanted to return a Result on failure, you can squash the implementation down to one line if you want:

use std::{
    fs::File,
    io::{self, BufRead, BufReader},
    path::Path,
};

fn lines_from_file(filename: impl AsRef<Path>) -> io::Result<Vec<String>> {
    BufReader::new(File::open(filename)?).lines().collect()
}

// ---

fn main() {
    let lines = lines_from_file("/etc/hosts").expect("Could not load lines");
    for line in lines {
        println!("{:?}", line);
    }
}

这篇关于读取文件并获取字符串数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆