Windows下获取重定向输入目录路径的Rust实现方案咨询
在Windows和Unix平台检查stdin是否指向目录的Rust实现
你的Unix版本代码依赖Unix特有的文件描述符API和/dev/stdin路径,Windows平台需要使用不同的系统API来实现相同逻辑。以下是跨平台的解决方案:
核心思路
- 跨平台句柄复制:Unix使用文件描述符(FD)克隆,Windows通过Win32 API复制stdin的句柄,避免直接操作原句柄导致后续stdin异常。
- 元数据检查:从复制后的句柄创建
File实例,统一调用metadata()判断是否为目录。 - 规范路径获取:Unix直接对
/dev/stdin调用canonicalize;Windows通过Win32 API获取文件真实路径。
依赖准备
在Cargo.toml中添加Windows平台所需的依赖:
[dependencies] windows = { version = "0.52", features = ["Win32_Foundation", "Win32_Storage_FileSystem", "Win32_System_Threading"] }
完整跨平台代码
use std::fs; use std::io::{self, stdin}; use std::path::PathBuf; #[cfg(unix)] use std::os::fd::{AsFd, OwnedFd}; #[cfg(windows)] use std::os::windows::io::{AsRawHandle, RawHandle}; #[cfg(windows)] use windows::Win32::Foundation::{HANDLE, MAX_PATH}; #[cfg(windows)] use windows::Win32::Storage::FileSystem::GetFinalPathNameByHandleW; #[cfg(windows)] use windows::Win32::System::Threading::{DuplicateHandle, DUPLICATE_SAME_ACCESS}; // 跨平台复制stdin的句柄/文件描述符 fn duplicate_stdin_handle() -> io::Result<RawHandle> { #[cfg(windows)] { let stdin_handle = stdin().as_raw_handle(); let mut dup_handle = HANDLE::default(); unsafe { DuplicateHandle( windows::Win32::System::Threading::GetCurrentProcess(), HANDLE(stdin_handle as isize), windows::Win32::System::Threading::GetCurrentProcess(), &mut dup_handle, 0, false, DUPLICATE_SAME_ACCESS, ) .ok()?; } Ok(dup_handle.0 as RawHandle) } #[cfg(unix)] { let fd = stdin().as_fd().try_clone_to_owned()?; Ok(fd.into()) } } // 跨平台获取stdin的规范路径 fn get_stdin_canonical_path() -> io::Result<PathBuf> { #[cfg(unix)] { fs::canonicalize("/dev/stdin") } #[cfg(windows)] { let handle = stdin().as_raw_handle(); let mut buf = [0u16; MAX_PATH as usize]; let len = unsafe { GetFinalPathNameByHandleW( HANDLE(handle as isize), &mut buf, MAX_PATH, 0, ) }; if len == 0 { return Err(io::Error::last_os_error()); } let wide_str = unsafe { std::ffi::OsStr::from_wide(&buf[..len as usize]) }; Ok(PathBuf::from(wide_str)) } } fn main() -> io::Result<()> { let handle = duplicate_stdin_handle()?; #[cfg(unix)] let file = std::fs::File::from(OwnedFd::from(handle)); #[cfg(windows)] let file = unsafe { std::fs::File::from_raw_handle(handle) }; let meta = file.metadata()?; if meta.is_dir() { let stdin_path = get_stdin_canonical_path()?; println!("{:?}", stdin_path); // 执行你的目录相关操作 } Ok(()) }
关键细节说明
- 句柄复制:Windows平台通过
DuplicateHandle复制stdin句柄,避免from_raw_handle接管原句柄导致后续stdin无法使用;Unix平台直接克隆文件描述符。 - 错误处理:替换原代码中的
unwrap()为?,遵循Rust错误处理规范,避免不必要的panic。 - 路径获取:Windows通过
GetFinalPathNameByHandleW获取文件的绝对路径,转换为Rust的PathBuf类型。
内容的提问来源于stack exchange,提问作者anon
相关产品推荐
相关产品推荐

