检查C#中的标准输入

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

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); 

文件参数工作正常,并将实用程序的输出传递给我的实用程序工作正常,但如果您只是正常调用它(没有参数和没有管道数据),它会挂起。 或者说,它阻止等待从标准读取。

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

 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流量的忠实粉丝,但是……呃。

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

但是,从.NET 4.5开始, Console实际上提供了一个新字段IsInputRedirected ,这使得这更简单,删除了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); 

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

看起来您应该能够使用一些Windows API调用来确定它。 Hans Passant的答案甚至还有一个辅助类来包装它。