【发布时间】:2011-03-28 01:30:30
【问题描述】:
我想编写一个具有不同行为的控制台应用程序,具体取决于输入是来自键盘还是来自文件。
有可能吗?在 C# 中最优雅的方式是什么?
【问题讨论】:
我想编写一个具有不同行为的控制台应用程序,具体取决于输入是来自键盘还是来自文件。
有可能吗?在 C# 中最优雅的方式是什么?
【问题讨论】:
您可以通过 p/调用 Windows FileType() API 函数来查找。这是一个帮助类:
using System;
using System.Runtime.InteropServices;
public static class ConsoleEx {
public static bool IsOutputRedirected {
get { return FileType.Char != GetFileType(GetStdHandle(StdHandle.Stdout)); }
}
public static bool IsInputRedirected {
get { return FileType.Char != GetFileType(GetStdHandle(StdHandle.Stdin)); }
}
public static bool IsErrorRedirected {
get { return FileType.Char != GetFileType(GetStdHandle(StdHandle.Stderr)); }
}
// P/Invoke:
private enum FileType { Unknown, Disk, Char, Pipe };
private enum StdHandle { Stdin = -10, Stdout = -11, Stderr = -12 };
[DllImport("kernel32.dll")]
private static extern FileType GetFileType(IntPtr hdl);
[DllImport("kernel32.dll")]
private static extern IntPtr GetStdHandle(StdHandle std);
}
用法:
bool inputRedirected = ConsoleEx.IsInputRedirected;
更新:这些方法已添加到 .NET 4.5 的 Console 类中。如果没有归属,我可能会添加:(只需使用相应的方法而不是这个帮助类。
https://msdn.microsoft.com/en-us/library/system.console.isoutputredirected.aspx https://msdn.microsoft.com/en-us/library/system.console.isinputredirected.aspx https://msdn.microsoft.com/en-us/library/system.console.iserrorredirected.aspx
【讨论】:
有趣的是,当管道打开时,System.Console.WindowHeight 和System.Console.WindowWidth 参数是零,我发现这是由于代码路径中的几个ArgumentOutOfRangeException 不关心控制台大小为零。
跨平台:在 Linux 和 Windows 上 MS dotNET 和 Mono 下的行为是相同的(我没有在 Mac 上尝试过)。
当使用管道传输 STDIN 或 STDOUT 时,控制台大小设置为 0。因此基于 Hans 的实现,我的代码如下:
using System;
public static class ConsoleEx {
public static bool IsConsoleSizeZero {
get {
try {
return (0 == (Console.WindowHeight + Console.WindowWidth));
}
catch (Exception exc){
return true;
}
}
}
public static bool IsOutputRedirected {
get { return IsConsoleSizeZero && !Console.KeyAvailable; }
}
public static bool IsInputRedirected {
get { return IsConsoleSizeZero && Console.KeyAvailable; }
}
}
2016 年更新:
向IsConsoleSizeZero 代码添加了异常处理,以提高代码在更广泛的上下文中的可用性。
代码似乎仍然运行良好,至少从使用 MonoDevelop / Xamarin Studio 的经验来看。
相关:
【讨论】:
Console.WindowHeight 不错!不过,我不太确定Console.KeyAvailable 的使用。一方面,完全可以同时重定向输入和输出,而您的代码将无法检测到这一点。
Lorenz 的回答是一个好的开始,可惜只能作为一个灵感。运行控制台应用程序的模式更多。
标准运行(在控制台中,没有任何重定向)
在控制台中一切正常。
使用标准输入和/或标准输出重定向从控制台执行重定向
例如
type input_file.txt | application.exe(在 Windows 中),或 application.exe <input_file.txt 用于输入重定向
(在 Linux 中将 type 替换为 cat)
或
application.exe | grep pattern 或 application.exe >output_file.txt 用于输出重定向
或
type input_file.txt | application.exe | grep pattern 或 application.exe <input_file.txt >output_file.txt 用于输入和输出重定向
从带有标准输出的控制台重定向执行和错误输出重定向
例如application.exe >output_file.txt 2>error_file.txt
使用隐藏控制台执行并重定向输入/输出/错误
例如来自 GUI 应用程序(控制台根本不可见)
使用隐藏控制台执行没有输入/输出/错误重定向
每种模式都有自己的“功能”。 Console.WindowHeight 和 Console.WindowWidth 在 Windows 中以标准方式用于第一和第二模式。在 Linux 中,第 2 和第 3 模式的返回值是 0。因此,在 Linux 中,您不能仅检测输入重定向。
因此,Lorenz answer 中的代码不能在所有情况下都用于检测重定向。读取Console.WindowHeight 或Console.WindowWidth 时的IOException 仅在(例如第3 模式)无输出 且仅适用于 时抛出>Windows。
要检测输入重定向(仅在Windows中)使用这个函数:
private static bool IsInputRedirected()
{
try
{
if (Console.KeyAvailable)
{
return (false);
}
}
catch (InvalidOperationException)
{
return (true);
}
return (false);
}
对于所有其他重定向和操作系统...尝试尝试如何检测它们。不同的控制台属性和函数'工作'(抛出异常,或零返回值)用于不同的模式。
在Windows 7 .NET Framework 4 Client Profile 和Mono JIT compiler version 4.2.1 (Debian 4.2.1.102+dfsg2-7ubuntu4) 上测试。
重要提示:
不要在 Linux 中使用此功能进行输入重定向(检测正在运行的操作系统/平台,例如 Windows 的 Mono),因为当您错误地期望重定向并且重定向未激活时,它可能会导致更多麻烦.
【讨论】:
由于框架 4.5 存在属性 Console.IsInputRedirected。 8-)
请参阅 Microsoft Docs:
https://docs.microsoft.com/en-us/dotnet/api/system.console.isinputredirected
【讨论】: