我目前正在阅读Michael的书“Linux编程接口”。这是第四章末的练习之一(我在铁锈工作,而不是C)。
tee程序在UNIX系统上的锈蚀实现。根据它的手册页
tee实用程序将标准输入复制到标准输出,在零或多个文件中复制。输出没有缓冲。
因此,运行echo "foo" | tee将打印"foo“到终端。运行echo "foo" | tee myfile会将"foo“打印到终端,并创建包含"foo”内容的文件myfile。
这是一个很小的例子,但我很想知道这是否是惯用的锈菌代码,以及是否可以提高效率。
use std::env;
use std::io::{self, Read};
use std::io::prelude::Write;
use std::error::Error;
use std::fs::File;
fn main() {
let fname = match env::args().nth(1) {
Some(name) => name,
None => String::from("/dev/null"),
};
let mut outfile = match File::create(&fname) {
Ok(file) => file,
Err(why) => panic!("{}", why.description()),
};
loop {
let mut line = String::new();
match io::stdin().read_to_string(&mut line) {
Ok(_) => {}
Err(_) => std::process::exit(0),
}
if line.is_empty() {
std::process::exit(0);
}
println!("{}", &line);
let _ = outfile.write(line.as_bytes());
}
}发布于 2016-10-19 12:58:13
高级别问题:
read_to_string:在此源中读取所有字节直到EOF,并将它们放入buf中。这意味着程序必须等待整个输入字符串存在才能写入单个字节。输入可能是千兆字节!cat不能与图像或压缩文件一起使用任何类型的二进制数据。更多战术问题:
use单个项目。序曲的意义是对所有你想要的东西进行全面的导入。Option或Result上存在的所有方法。例如,unwrap_or_else封装默认值大小写。/dev/null将实现与特定的操作系统联系在一起(也许可以,因为您正在制作cat),但也与文件系统布局有关。当cat不可用时,不能使用此/dev/,这很可能是在系统紧急情况下发生的。最好是程序不写任何东西,而不是写到/dev/null。description显示的信息比打印错误少:其他os错误Is是一个目录(os错误21)expect可能比match或unwrap_or_else更紧凑,这取决于所需的错误格式。println!时不需要传递引用;该宏自动引用所有参数。let _是一个非常大的危险信号。cat几乎没有什么责任,但是正确地编写输出是相当关键的!当写入失败时,程序应该退出,例如当管道关闭时。use std::env;
use std::io::{self, Read, Write};
use std::fs::File;
fn main() {
let fname = env::args().nth(1).unwrap_or_else(|| String::from("/dev/null"));
let mut outfile = File::create(&fname).expect("Unable to create file");
let mut line = String::new();
loop {
line.clear();
io::stdin().read_to_string(&mut line).unwrap_or_else(|_| {
std::process::exit(0)
});
if line.is_empty() {
std::process::exit(0);
}
println!("{}", line);
outfile.write(line.as_bytes()).expect("Unable to write!");
}
}很抱歉有点离题了,但问题很有趣。我可能会写得像这样:
use std::env;
use std::io::{self, Read, Write};
use std::fs::File;
const BUFFER_SIZE: usize = 8 * 1024;
fn main() {
let mut buf = vec![0; BUFFER_SIZE];
let stdin = io::stdin();
let mut stdin = stdin.lock();
let stdout = io::stdout();
let stdout = stdout.lock();
let mut outputs: Vec<_> = env::args().skip(1).map(|fname| {
let f = File::create(&fname).unwrap_or_else(|e| {
panic!("Unable to create file {}: {}", fname, e);
});
Box::new(f) as Box<Write>
}).collect();
outputs.push(Box::new(stdout));
loop {
let bytes = stdin.read(&mut buf).expect("Unable to read input");
if bytes == 0 { break }
// **Very important**, otherwise you can end up with
// Heartbleed-esque bugs! I'm chosing to shadow `buf` to
// deliberately prevent using it again in this loop.
let buf = &buf[..bytes];
for output in &mut outputs {
output.write_all(buf).expect("Unable to write output");
}
}
}https://codereview.stackexchange.com/questions/144628
复制相似问题