在C#中检查标准输入
在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("错误,需要数据"); 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("错误,需要数据"); 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("错误,需要数据"); return; } catch(InvalidOperationException) { reader = Console.In; } } Process(reader);
对于像这样的流程,我不是太喜欢使用异常,但是...嗯。
在这段内容中,作者提到了一个关于在C#中检查标准输入的问题。作者开始使用了Pieter的解决方案,但后来意识到这种方法在Mono中不起作用。当使用管道输入时,Mono不会抛出异常来检索Console.KeyAvailable,因此这种方法没有帮助。
然而,从.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);
作者在重新访问这个问题时表示,这听起来是新的正确答案。很酷!
在C#中,检查标准输入的问题出现的原因是没有内置的方法来检测输入是否来自于标准输入(控制台)还是来自于文件重定向。解决这个问题的方法是使用try/catch语句来包裹Console.KeyAvailable方法,如果抛出异常,则说明输入是通过文件重定向的。然而,这种方法在Mono环境下似乎不起作用。幸运的是,从.NET 4.5开始,有一种更简单的解决方案。
在.NET 4.5中,可以使用Console.IsInputRedirected属性来判断输入是否来自于标准输入。以下是代码示例:
bool isInputRedirected = Console.IsInputRedirected; if (isInputRedirected) { Console.WriteLine("输入来自于文件重定向"); } else { Console.WriteLine("输入来自于标准输入"); }
通过使用Console.IsInputRedirected属性,可以更简单地确定输入的来源。这种方法不需要使用try/catch语句,因此更可靠和高效。
总结起来,检查标准输入的问题在C#中出现的原因是缺乏内置方法来判断输入的来源,解决方法是使用try/catch语句或Console.IsInputRedirected属性来检测输入是否来自于标准输入。从.NET 4.5开始,推荐使用Console.IsInputRedirected属性来实现更简单和可靠的检查。
在C#中检查标准输入的原因是需要通过Windows API调用来确定。Hans Passant在他的回答中甚至提供了一个帮助类来包装所有操作。
以下是Hans Passant提供的帮助类代码:
using System; using System.Runtime.InteropServices; public static class NativeMethods { [DllImport("kernel32.dll", SetLastError = true)] private static extern bool GetStdHandle(int nStdHandle, out IntPtr handle); [DllImport("kernel32.dll")] private static extern bool GetConsoleMode(IntPtr handle, out int mode); private const int STD_INPUT_HANDLE = -10; private const int ENABLE_ECHO_INPUT = 0x4; public static bool IsInputRedirected() { IntPtr handle; handle = GetStdHandle(STD_INPUT_HANDLE); if (handle == IntPtr.Zero) return false; int mode; if (!GetConsoleMode(handle, out mode)) return true; return (mode & ENABLE_ECHO_INPUT) != ENABLE_ECHO_INPUT; } }
使用以上帮助类,可以通过调用`NativeMethods.IsInputRedirected()`方法来检查标准输入是否被重定向。
使用示例:
static void Main(string[] args) { bool isInputRedirected = NativeMethods.IsInputRedirected(); Console.WriteLine("Is input redirected? " + isInputRedirected); }
以上就是在C#中检查标准输入的原因和解决方法的介绍。通过使用Hans Passant提供的帮助类,我们可以轻松地判断标准输入是否被重定向。