在命令行上接受可选文件,默认为stdin

发布于 2025-01-21 13:41:27 字数 1741 浏览 3 评论 0 原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

昇り龍 2025-01-28 13:41:27

您可以使用 option< pathbuf> 并使用 stdin none 时,所有内容都包含在方法中(是,您必须实现它自己):

use std::io::BufReader;
use clap;
use std::io::BufRead;
use std::path::PathBuf; // 3.1.6

#[derive(clap::Parser)]
struct Reader {
    input: Option<PathBuf>,
}

impl Reader {
    fn reader(&self) -> Box<dyn BufRead> {
        self.input.as_ref()
            .map(|path| {
                Box::new(BufReader::new(std::fs::File::open(path).unwrap())) as Box<dyn BufRead>
            })
            .unwrap_or_else(|| Box::new(BufReader::new(std::io::stdin())) as Box<dyn BufRead>)
    }
}

You can use an Option<PathBuf> and use stdin when None, everything wrapped into a method (yes, you have to implement it yourself):

use std::io::BufReader;
use clap;
use std::io::BufRead;
use std::path::PathBuf; // 3.1.6

#[derive(clap::Parser)]
struct Reader {
    input: Option<PathBuf>,
}

impl Reader {
    fn reader(&self) -> Box<dyn BufRead> {
        self.input.as_ref()
            .map(|path| {
                Box::new(BufReader::new(std::fs::File::open(path).unwrap())) as Box<dyn BufRead>
            })
            .unwrap_or_else(|| Box::new(BufReader::new(std::io::stdin())) as Box<dyn BufRead>)
    }
}

Playground

扛刀软妹 2025-01-28 13:41:27

该解决方案:不使用动态调度,是详细的,使用 default_value_t ,需要夜间参见 #93965 (应该不需要每晚都需要,但对我来说更简单)

use clap; // 3.1.6

use std::fmt::{self, Display, Formatter};
use std::fs::File;
use std::io::{self, stdin, BufRead, BufReader, Read, StdinLock};
use std::str::FromStr;

enum Input {
    Stdin(StdinLock<'static>),
    File(BufReader<File>),
}

impl Display for Input {
    fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), fmt::Error> {
        write!(fmt, "Input")
    }
}

impl Default for Input {
    fn default() -> Self {
        Self::Stdin(stdin().lock())
    }
}

impl FromStr for Input {
    type Err = io::Error;

    fn from_str(path: &str) -> Result<Self, <Self as FromStr>::Err> {
        File::open(path).map(BufReader::new).map(Input::File)
    }
}

impl BufRead for Input {
    fn fill_buf(&mut self) -> Result<&[u8], io::Error> {
        match self {
            Self::Stdin(stdin) => stdin.fill_buf(),
            Self::File(file) => file.fill_buf(),
        }
    }

    fn consume(&mut self, amt: usize) {
        match self {
            Self::Stdin(stdin) => stdin.consume(amt),
            Self::File(file) => file.consume(amt),
        }
    }
}

impl Read for Input {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
        match self {
            Self::Stdin(stdin) => stdin.read(buf),
            Self::File(file) => file.read(buf),
        }
    }
}

#[derive(clap::Parser)]
struct Reader {
    #[clap(default_value_t)]
    input: Input,
}

This solution: Doesn't use dynamic dispatch, is verbose, use default_value_t, require nightly see #93965 (It should be possible to not require nightly but it's was simpler for me)

use clap; // 3.1.6

use std::fmt::{self, Display, Formatter};
use std::fs::File;
use std::io::{self, stdin, BufRead, BufReader, Read, StdinLock};
use std::str::FromStr;

enum Input {
    Stdin(StdinLock<'static>),
    File(BufReader<File>),
}

impl Display for Input {
    fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), fmt::Error> {
        write!(fmt, "Input")
    }
}

impl Default for Input {
    fn default() -> Self {
        Self::Stdin(stdin().lock())
    }
}

impl FromStr for Input {
    type Err = io::Error;

    fn from_str(path: &str) -> Result<Self, <Self as FromStr>::Err> {
        File::open(path).map(BufReader::new).map(Input::File)
    }
}

impl BufRead for Input {
    fn fill_buf(&mut self) -> Result<&[u8], io::Error> {
        match self {
            Self::Stdin(stdin) => stdin.fill_buf(),
            Self::File(file) => file.fill_buf(),
        }
    }

    fn consume(&mut self, amt: usize) {
        match self {
            Self::Stdin(stdin) => stdin.consume(amt),
            Self::File(file) => file.consume(amt),
        }
    }
}

impl Read for Input {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
        match self {
            Self::Stdin(stdin) => stdin.read(buf),
            Self::File(file) => file.read(buf),
        }
    }
}

#[derive(clap::Parser)]
struct Reader {
    #[clap(default_value_t)]
    input: Input,
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文