前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >.NET CORE 怎么样从控制台中读取输入流

.NET CORE 怎么样从控制台中读取输入流

作者头像
梁规晓
发布2019-09-03 18:21:31
7470
发布2019-09-03 18:21:31
举报
文章被收录于专栏:DotNet程序园DotNet程序园

从Console.ReadList/Read 的源码中,可学习到.NET CORE 是怎么样来读取输入流。

也可以学习到是如何使用P/Invoke来调用系统API

Console.ReadList 的源码为

代码语言:javascript
复制
[MethodImplAttribute(MethodImplOptions.NoInlining)]
public static string ReadLine()
{
    return In.ReadLine();
}

其中In为。

代码语言:javascript
复制
internal static T EnsureInitialized<T>(ref T field, Func<T> initializer) where T : class =>
    LazyInitializer.EnsureInitialized(ref field, ref InternalSyncObject, initializer);
public static TextReader In => EnsureInitialized(ref s_in, () => ConsolePal.GetOrCreateReader());

可以看到他是个TextRead 接下来,我们看看ConsolePal.GetOrCreateReader()方法中,是怎么样获取到一个Reader的。 转到ConsolePal.Windows.cs 的源码,可以看到,

代码语言:javascript
复制
internal static TextReader GetOrCreateReader()
{
    Stream inputStream = OpenStandardInput();
    return SyncTextReader.GetSynchronizedTextReader(inputStream == Stream.Null ?
        StreamReader.Null :
        new StreamReader(
            stream: inputStream,
            encoding: new ConsoleEncoding(Console.InputEncoding),
            detectEncodingFromByteOrderMarks: false,
            bufferSize: Console.ReadBufferSize,
            leaveOpen: true));
}

继续跳转,查看方法OpenStandardInput

代码语言:javascript
复制
public static Stream OpenStandardInput()
{
    return GetStandardFile(Interop.Kernel32.HandleTypes.STD_INPUT_HANDLE, FileAccess.Read);
}

继续看方法

代码语言:javascript
复制
private static Stream GetStandardFile(int handleType, FileAccess access)
{
    IntPtr handle = Interop.Kernel32.GetStdHandle(handleType);
    // 此处源码一坨注释被我删掉了。^_^
    if (handle == IntPtr.Zero || handle == InvalidHandleValue ||
        (access != FileAccess.Read && !ConsoleHandleIsWritable(handle)))
    {
        return Stream.Null;
    }
    return new WindowsConsoleStream(handle, access, GetUseFileAPIs(handleType));
}

哈哈,终于要看到了Interop.Kernel32.GetStdHandle 这个方法就是调用系统API接口函数的方法。 在Interop.GetStdHandle.cs 中调用GetStdHandle 的系统API 在 System.Console.csproj 的项目文件中。 可以看到,在项目文件中,使用条件编译,将不同的文件包含进来,调用不同系统的API

代码语言:javascript
复制
<!-- Windows -->
  <ItemGroup Condition="'$(TargetsWindows)' == 'true'">
    <Compile Include="$(CommonPath)\CoreLib\Interop\Windows\Kernel32\Interop.GetStdHandle.cs">
          <Link>Common\CoreLib\Interop\Windows\Interop.GetStdHandle.cs</Link>
        </Compile>
</ItemGroup>
<!-- Unix -->
<ItemGroup Condition=" '$(TargetsUnix)' == 'true'">
</ItemGroup>

回到GetStandardFile 中看到返回一个WindowsConsoleStream 其中Read方法,调用了系统API。

代码语言:javascript
复制
private static unsafe int ReadFileNative(IntPtr hFile, byte[] bytes, int offset, int count, bool isPipe, out int bytesRead, bool useFileAPIs)
{
    if (bytes.Length - offset < count)
        throw new IndexOutOfRangeException(SR.IndexOutOfRange_IORaceCondition);
    // You can't use the fixed statement on an array of length 0.
    if (bytes.Length == 0)
    {
        bytesRead = 0;
        return Interop.Errors.ERROR_SUCCESS;
    }
    bool readSuccess;
    fixed (byte* p = &bytes[0])
    {
        if (useFileAPIs)
        {
            readSuccess = (0 != Interop.Kernel32.ReadFile(hFile, p + offset, count, out bytesRead, IntPtr.Zero));
        }
        else
        {
            int charsRead;
            readSuccess = Interop.Kernel32.ReadConsole(hFile, p + offset, count / BytesPerWChar, out charsRead, IntPtr.Zero);
            bytesRead = charsRead * BytesPerWChar;
        }
    }
    if (readSuccess)
        return Interop.Errors.ERROR_SUCCESS;
        
    int errorCode = Marshal.GetLastWin32Error();
    if (errorCode == Interop.Errors.ERROR_NO_DATA || errorCode == Interop.Errors.ERROR_BROKEN_PIPE)
        return Interop.Errors.ERROR_SUCCESS;
    return errorCode;
}

useFileAPIs 参数,决定是使用操作系统 ReadFile还是 ReadConsole API。 这2个API。都是可以读取到控制台的输入流。


对于.NET CORE 源码中有很多 XXXX.Unix.cs,XXXX.Windows.cs 类名都是XXXX.例如 ConsolePal 这个内部类。 使用条件条件编译。达到不同平台使用对应的 OS API来调用。

代码语言:javascript
复制
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-09-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet程序园 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档