You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows下获取重定向输入目录路径的Rust实现方案咨询

在Windows和Unix平台检查stdin是否指向目录的Rust实现

你的Unix版本代码依赖Unix特有的文件描述符API和/dev/stdin路径,Windows平台需要使用不同的系统API来实现相同逻辑。以下是跨平台的解决方案:

核心思路

  1. 跨平台句柄复制:Unix使用文件描述符(FD)克隆,Windows通过Win32 API复制stdin的句柄,避免直接操作原句柄导致后续stdin异常。
  2. 元数据检查:从复制后的句柄创建File实例,统一调用metadata()判断是否为目录。
  3. 规范路径获取: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 08:34:58