从stdin无阻塞读取字节

时间:2017-07-08 17:50:40

标签: c# mono stdin nonblocking

我想以下列方式从C#mono进程的标准输入(标准输入)中读取一个字节(或字符):

  • 如果已经有可用于从stdin读取的字节,则返回第一个
  • 如果没有可用于从stdin读取的字节,则无需等待任何内容或阻止
  • 继续
  • 如果有线程或异步,它应该是succint和可证明正确的按需获取单个字节的插入式解决方案
  • stdin可能是管道或文件,因此Console.KeyAvailable将无法执行

感谢。

1 个答案:

答案 0 :(得分:3)

如果您的平台具有System.Collections.Concurrent.BlockingCollection的实施,这是一种简单易用的方法:

class ConsoleReader {
  private readonly BlockingCollection<int> buffer = new BlockingCollection<int>(1);
  private readonly Thread readThread;
  public ConsoleReader() {
    readThread = new Thread(() => {
      if (Console.IsInputRedirected) {
        int i;
        do {
          i = Console.Read();
          buffer.Add(i);
        } while (i != -1);
      } else {
        while (true) { 
          var consoleKeyInfo = Console.ReadKey(true);
          if (consoleKeyInfo.KeyChar == 0) continue;  // ignore dead keys
          buffer.Add(consoleKeyInfo.KeyChar);
        }
      }
    });
  }

  public void Start() {
    readThread.Start();
  }

  public int? Next {
    get {
      int result;
      return buffer.TryTake(out result, 0) ? result : default(int?);
    }
  }
}

免责声明:这个答案实际上并未在Mono上进行过测试,只是简单地在完整的.NET平台上进行了测试。 您可以使用Task代替Thread,正确取消等来增加这一点,但这不会改变显式等待同步操作的中心效率低({{1} }和Console.Read都是)。 .NET本身不提供便携式异步控制台I / O.可以跨平台实现自己(使用操作系统功能),但显然非常重要。