读取文件并获取字符串数组 [英] Read a file and get an array of strings
问题描述
我想读取一个文件并获取一个 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!("{:?}",行);}}
- 在另一个答案中,使用对文件名实现
AsRef
的泛型类型是值得的. -
Result :: expect
缩短了Err
的恐慌. -
BufRead :: lines
处理多种类型的换行符,而不仅仅是"\ n"
. -
BufRead :: lines
还为您提供了单独分配的String
s,而不是一个大问题. - 没有理由仅仅为了返回临时变量而将其收集到临时变量中.
尤其没有理由重复类型(
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 String
s. 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 aString
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);
}
}
- As in the other answer, it's worth it to use a generic type that implements
AsRef
for the filename. Result::expect
shortens the panic onErr
.BufRead::lines
handles multiple types of newlines, not just"\n"
.BufRead::lines
also gives you separately allocatedString
s, instead of one big glob.- 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屋!