Stderr
文件描述符,但似乎没有它的实现,并且我没有看到与 C/C++ 中的 dup2
类似的任何内容的明确路线。
我已经尝试过:
Read
(impl Read for Stderr
),但需要整个代码库才能覆盖。消耗文件描述符中的数据,然后进入
File
,然后进入ReadBuf
trait FDReader {
fn consume(&mut self);
}
impl FDReader for Stderr {
fn consume(&mut self) {
let f = std::fs::File::from_raw_fd(self.as_raw_fd());
let mut extract = String::new();
BufReader::new(f).read_to_string(&mut extract);
}
}
我专注于
consume
,因为我在测试代码时不必完全返回任何内容,尽管这不起作用。由于我在Linux系统上运行,而且我不打算发布代码,所以我还考虑过重定向
/proc/self/fd/2 -> /dev/null
,然后当我想写入那里时返回原始指针引用。对于这个范围来说,这已经超出了极限。我也想过直接使用
libc::dup2
- 尽管我已经厌倦了。
标准库中没有办法做到这一点1。 gag crate 允许将 stderr 或 stdout 重定向到文件或不重定向到任何内容,但它仅适用于 *nix 系统。
从不同的角度来看问题,我鼓励您根本不直接使用 stdout 或 stderr 。相反,使用“依赖注入”来传递可写入的值。不要使用 println
,而使用
writeln
。另请参阅:
这不是严格正确的。您是否注意到在测试期间stdout 和 stderr 没有输出?这是因为编译器(和测试套件)使用了一对不稳定的隐藏函数,它们允许更改 stdout 和 stderr 的线程本地实例。 另请参阅:
在较低级别上完成此操作。 即,在程序打开更多文件之前,删除并替换标准文件描述符 0 (stdin)、1 (stdout) 和 2 (stderr)。
它依赖于这样一个事实:
libc
将为新打开的文件分配可用的第一个(最低)描述符。这是由 POSIX
保证的。在 C 语言中,可以使用
FILE* stdout
重新分配
fdopen()
,并且,当 printf()
和其他人使用 FILE* stdout
时,这就能达到目的。
但是 Rust 的标准库使用文件描述符,因此我们必须依赖操作系统或
libc
stdout
use std::ffi::c_char;
use libc;
fn main() {
unsafe {
let out_file_path = "console.txt".to_string().as_ptr() as *const c_char;
// let open_flag = libc::O_WRONLY | libc::O_CREAT | libc::O_APPEND | libc::FD_CLOEXEC;
libc::close(libc::STDOUT_FILENO);
let new_fd = libc::creat(out_file_path, libc::S_IRUSR | libc::S_IWUSR);
if new_fd < 0 {
libc::perror(std::ptr::null());
}
eprintln!("new fd: {}, expected {}", new_fd, libc::STDOUT_FILENO);
}
println!("Yohoho!");
}
还必须有一种在 Windows 上执行此操作的方法,就像这个问题中那样,但我会将其作为练习留给读者。