我正在尝试编写一个 Rust 程序,该程序在stdin.
在 Windows 上,我可能会从一个cmd窗口中调用它,例如:
dir /b /s | findstr .*,v$ | rust-prog -n
Run Code Online (Sandbox Code Playgroud)
在 Unix 上,我会使用类似的东西:
find . -name '*,v' -print0 | rust-prog -0
Run Code Online (Sandbox Code Playgroud)
我无法将收到的内容stdin转换为std::path::Path. 据我了解,要获得可在 Windows 或 Unix 上编译的内容,我将需要使用条件编译,std::os::windows::ffi或std::os::unix::ffi视情况而定。
此外,似乎在 Windows 上我需要使用kernel32::MultiByteToWideChar当前代码页来创建std::os::windows::ffi::OsStrExt.
有没有更简单的方法来做到这一点?我的建议甚至看起来可行吗?
例如,将字符串转换为路径很容易,因此我尝试使用以下字符串处理函数stdin:
use std::io::{self, Read};
fn main() {
let mut buffer = String::new();
match io::stdin().read_line(&mut buffer) {
Ok(n) => println!("{}", buffer),
Err(error) => println!("error: {}", error)
}
}
Run Code Online (Sandbox Code Playgroud)
在 Windows 上,如果我有一个包含单个文件的目录¿.txt(即 0xbf)。并将名称通过管道传输到stdin. 我得到:error: stream did not contain valid UTF-8。
这是一个看起来合理的 Windows 版本。使用 win32api 函数将控制台提供的字符串转换为宽字符串,然后使用OsString::from_wide.
我还不确信它使用了正确的代码页。dir似乎使用 OEM 代码页,所以也许这应该是默认值。控制台中的输入代码页和输出代码页之间也有区别。
在我的Cargo.toml
[dependencies]
winapi = "0.2"
kernel32-sys = "0.2.2"
Run Code Online (Sandbox Code Playgroud)
根据问题读取通过 Windows 上的 stdin 传输的文件名列表的代码。
extern crate kernel32;
extern crate winapi;
use std::io::{self, Read};
use std::ptr;
use std::fs::metadata;
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
/// Convert windows console input to wide string that can
/// be used by OS functions
fn wide_from_console_string(bytes: &[u8]) -> Vec<u16> {
assert!(bytes.len() < std::i32::MAX as usize);
let mut wide;
let mut len;
unsafe {
let cp = kernel32::GetConsoleCP();
len = kernel32::MultiByteToWideChar(cp, 0, bytes.as_ptr() as *const i8, bytes.len() as i32, ptr::null_mut(), 0);
wide = Vec::with_capacity(len as usize);
len = kernel32::MultiByteToWideChar(cp, 0, bytes.as_ptr() as *const i8, bytes.len() as i32, wide.as_mut_ptr(), len);
wide.set_len(len as usize);
}
wide
}
/// Extract paths from a list supplied as Cr LF
/// separated wide string
/// Would use a generic split on substring if it existed
fn paths_from_wide(wide: &[u16]) -> Vec<OsString> {
let mut r = Vec::new();
let mut start = 0;
let mut i = start;
let len = wide.len() - 1;
while i < len {
if wide[i] == 13 && wide[i + 1] == 10 {
if i > start {
r.push(OsString::from_wide(&wide[start..i]));
}
start = i + 2;
i = i + 2;
} else {
i = i + 1;
}
}
if i > start {
r.push(OsString::from_wide(&wide[start..i]));
}
r
}
fn main() {
let mut bytes = Vec::new();
if let Ok(_) = io::stdin().read_to_end(&mut bytes) {
let pathlist = wide_from_console_string(&bytes[..]);
let paths = paths_from_wide(&pathlist[..]);
for path in paths {
match metadata(&path) {
Ok(stat) => println!("{:?} is_file: {}", &path, stat.is_file()),
Err(e) => println!("Error: {:?} for {:?}", e, &path)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
567 次 |
| 最近记录: |