C#控制台如何使用管道接收输入

48

我知道如何编写带参数的控制台应用程序,例如:myProgram.exe param1 param2。

我的问题是,如何使我的程序与 | 一起使用,例如:echo "word" | myProgram.exe?

8个回答

50

如果要读取用户的输入,你需要使用Console.Read()Console.ReadLine()。管道可以透明地替换用户输入。虽然同时使用两者也是可能的,但并不容易。

编辑:

一个简单的类似于cat的程序:

class Program
{
    static void Main(string[] args)
    {
        string s;
        while ((s = Console.ReadLine()) != null)
        {
            Console.WriteLine(s);
        }

    }
}

当运行时,如预期的那样,输出结果为:

C:\...\ConsoleApplication1\bin\Debug>echo "Foo bar baz" | ConsoleApplication1.exe
"Foo bar baz"
C:\...\ConsoleApplication1\bin\Debug>

1
你的示例是否适用于:echo“Foo bar baz”| ConsoleApplication1.exe | ConsoleApplication1.exe? - Patrick Desjardins
3
是的。使用一个比较简单的类比,管道实际上是将第一个应用程序的Stdout流插入到管道中下一个应用程序的Stdin流中。控制台的stdin通过第一个应用程序处理,最后一个应用程序的stdout被显示出来。 - Matthew Scharley
1
如果您正在处理二进制数据:https://dev59.com/5HI_5IYBdhLWcg3wBuNs - sanmai
为什么要检查ReadLine == null,它会返回null吗?(如果没有输入,它不会返回空字符串吗)。https://dev59.com/PoTba4cB1Zd3GeqP3DgJ - barlop
@barlop 不,它不会返回空字符串。那么你如何检索空行呢?Console.ReadLine 的文档说明如果没有更多的行可读,则返回 null:https://msdn.microsoft.com/de-de/library/system.console.readline(v=vs.110).aspx - Robert S.
@RobertS。是的,谢谢,非常正确,顺便说一下,它只在按下Ctrl-Z时返回null(例如不是Ctrl-C),因此不是“没有更多行可读”的情况。我看到msdn提到了Ctrl+Z。 - barlop

20
以下内容不会阻止应用程序输入并在数据被传输或未被传输时起作用。这有点像一个hack;由于错误捕获,当进行大量传输调用时可能会影响性能,但是...很容易。
public static void Main(String[] args)
{

    String pipedText = "";
    bool isKeyAvailable;

    try
    {
        isKeyAvailable = System.Console.KeyAvailable;
    }
    catch (InvalidOperationException expected)
    {
        pipedText = System.Console.In.ReadToEnd();
    }

    //do something with pipedText or the args
}

1
在stackoverflow.com的这个问题中,hans passant提到了一个更好的方法:System.Console.WriteLine(System.Console.IsInputRedirected.ToString()); - barlop

15

在 .NET 4.5 中,它是

if (Console.IsInputRedirected)
{
    using(stream s = Console.OpenStandardInput())
    {
        ...

嗨,我似乎无法通过这段代码使其正常工作,有什么想法吗? - daniel metlitski

10

这是做法:

static void Main(string[] args)
{
    Console.SetIn(new StreamReader(Console.OpenStandardInput(8192))); // This will allow input >256 chars
    while (Console.In.Peek() != -1)
    {
        string input = Console.In.ReadLine();
        Console.WriteLine("Data read was " + input);
    }
}

这种方法有两种用法。从标准输入读取:

C:\test>myProgram.exe
hello
Data read was hello

或从管道输入读取:

C:\test>echo hello | myProgram.exe
Data read was hello

4
这里有另一种替代方案,它是从其他解决方案加上 peek() 组合而成的。
没有 Peek(),当使用“type t.txt | prog.exe”处理多行文件时,我发现应用程序无法返回,只能通过 ctrl-c 结束。但仅使用“prog.exe”或“echo hi | prog.exe”则可以正常工作。
此代码仅用于处理管道输入。
static int Main(string[] args)
{
    // if nothing is being piped in, then exit
    if (!IsPipedInput())
        return 0;

    while (Console.In.Peek() != -1)
    {
        string input = Console.In.ReadLine();
        Console.WriteLine(input);
    }

    return 0;
}

private static bool IsPipedInput()
{
    try
    {
        bool isKey = Console.KeyAvailable;
        return false;
    }
    catch
    {
        return true;
    }
}

2
在stackoverflow上,Hans Passant的回答中提到了一种更好的方法:System.Console.WriteLine(System.Console.IsInputRedirected.ToString());,可以检测控制台输入流是否被重定向。 - barlop

3

这也适用于

c:\MyApp.exe < input.txt

我不得不使用StringBuilder来处理从标准输入中捕获的输入:

public static void Main()
{
    List<string> salesLines = new List<string>();
    Console.InputEncoding = Encoding.UTF8;
    using (StreamReader reader = new StreamReader(Console.OpenStandardInput(), Console.InputEncoding))
    {
        string stdin;
        do
        {
            StringBuilder stdinBuilder = new StringBuilder();
            stdin = reader.ReadLine();
            stdinBuilder.Append(stdin);
            var lineIn = stdin;
            if (stdinBuilder.ToString().Trim() != "")
            {
                salesLines.Add(stdinBuilder.ToString().Trim());
            }

        } while (stdin != null);

    }
}

2

Console.In是一个围绕标准输入流包装的TextReader引用。当将大量数据传输到程序中时,使用这种方式可能更容易处理。


1

提供的示例存在问题。

  while ((s = Console.ReadLine()) != null)
如果程序在没有管道数据的情况下启动,将会一直等待输入。因此用户必须手动按任意键退出程序。

1
这段代码与程序相关,翻译成中文为:只是一个更有价值的评论,并且其他人已经解决了它并提供了解决方案。 - barlop

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接