检查C#中的标准输入

时间:2010-10-18 17:13:24

标签: c# .net console stdin

我正在编写一个小命令行实用程序,其目的是解析另一个实用程序的输出。我希望它可以通过两种方式调用:

c:\> myutility filewithoutput.txt

或者,

c:\> otherutility -args | myutility

所以,基本上,标准输入或文件参数。我对此的第一次尝试看起来像这样:

TextReader reader;

if (args.Length > 1) {
    reader = new StreamReader(new FileStream(args[1], FileMode.Open));
} else {
    reader = Console.In;
}

Process(reader);

file参数工作正常,并且将实用程序的输出汇总到我的实用程序工作正常,但如果你只是正常调用它(没有参数和没有管道数据),它就会挂起。或者更确切地说,它阻止等待从标准读取。

我的第二稿看起来像这样:

TextReader reader;

if (args.Length > 1) {
    reader = new StreamReader(new FileStream(args[1], FileMode.Open));
} else {
    if(Console.KeyAvailable) {
        reader = Console.In;
    } else {
        Console.WriteLine("Error, need data");
        return;
    }
}

Process(reader);

虽然KeyAvailable修复了“无输入”问题,但如果您尝试输入数据> _<

,则会引发异常
Unhandled Exception: System.InvalidOperationException: Cannot see if a key
has been pressed when either application does not have a console or when
console input has been redirected from a file. Try Console.In.Peek.

at System.Console.get_KeyAvailable()
at MyUtility.Program.Main(String[] args) in Program.cs:line 39

例外建议我使用Console.In.Peek,所以我的下一个草案就是这样:

TextReader reader;

if (args.Length > 1) {
    reader = new StreamReader(new FileStream(args[1], FileMode.Open));
} else {
    if(Console.In.Peek() != 0) {
        reader = Console.In;
    } else {
        Console.WriteLine("Error, need data");
        return;
    }
}

Process(reader);

然而,这与第一次尝试有同样的问题:它阻塞,寻找输入。 哎呀!

我有什么遗失的吗?

旁注:我知道参数“ - ”的约定意味着“使用标准输入”。如果没有别的办法,我会用它。但是,肯定有一些方法可以检测标准输入是否是控制台!

编辑:这是似乎做我需要的最终版本:

TextReader reader;

if (args.Length > 1) {
    reader = new StreamReader(new FileStream(args[1], FileMode.Open));
} else {
    try {
        bool tmp = Console.KeyAvailable;
        Console.WriteLine("Error, need data");
        return;
    } catch(InvalidOperationException) {
        reader = Console.In;
    }
}

Process(reader);

不喜欢像这样使用Exceptions流,但是......呃。

3 个答案:

答案 0 :(得分:10)

快速而肮脏的方法是将Console.KeyAvailable包装在try / catch中,如果抛出,则表示输入是从文件重定向的。当您找不到合适的方法来检查状态时,使用try / catch检测状态并不是很常见。

答案 1 :(得分:5)

我一直在使用Pieter的解决方案,直到我意识到它在Mono中不起作用。使用管道输入检索Console.KeyAvailable时,Mono不会抛出异常,因此该方法无效。

但是,从.NET 4.5开始,Console实际上提供了一个新字段IsInputRedirected,这使得这更加简单,删除了默认设置和不必要的try / catch

TextReader reader;

if (args.Length > 1) {
    reader = new StreamReader(new FileStream(args[1], FileMode.Open));
} else {
    if (Console.IsInputRedirected) {
        reader = Console.In;
    } else {
        Console.WriteLine("Error, need data");
        return;
    }
}

Process(reader);

答案 2 :(得分:1)

看起来你应该可以使用一些Windows API调用来确定它。 Hans Passant's answer甚至还有一个辅助类来包装它。