我希望从我的 C# 项目中另一个应用程序的标准输出流中解析 UTF8 字符。使用默认方法,从进程的标准输出流读取时,ANSI 范围之外的字符会被损坏。
现在根据微软的说法,我需要做的是设置StandardOutputEncoding:
如果 StandardOutputEncoding 属性的值为 Nothing,则进程对标准输出使用默认的标准输出编码。必须在进程启动之前设置 StandardOutputEncoding 属性。设置此属性并不能保证进程将使用指定的编码。应测试应用程序以确定该进程支持哪些编码。
但是,尝试将 StandardOutputEncoding 设置为 UTF8/CP65001,当转储到二进制文件时,读取的输出显示相同的外语字符阉割。它们总是读作“?” (又名 0x3F)而不是它们应该的样子。
我知道此时的假设是我正在解析其输出的应用程序根本不发送 UTF8 输出,但当我尝试将应用程序的输出从命令行转储到文件时,情况绝对不是这样将命令提示符的代码页强制为 65001 后,一切看起来都很好。
chcp 65001 && slave.exe > file.txt
由此,我知道应用程序 Slave.exe 能够输出 UTF8 编码的标准输出,但尽我所能,我无法让 StandardOutputEncoding 在我的 C# 应用程序中执行相同的操作。
每次我最终处理 .NET 中的编码时,我都希望自己能回到 C++ 世界,因为一切都需要更多工作,但更加透明。我正在考虑编写一个 C 应用程序来将slave.txt 的输出读取到一个 UTF8 编码的文本文件中,以供 C# 解析,但我现在暂缓采用这种方法。
StandardOutputEncoding 的唯一影响对执行的应用程序的标准输出没有任何影响。它所做的唯一事情是设置位于从正在运行的应用程序捕获的二进制标准输出流顶部的 StreamReader 的编码。
这对于本机输出 UTF8 或 Unicode 标准输出的应用程序来说是可以的,但大多数 Microsoft 实用程序会不这样做,而只会根据控制台的代码页对结果进行编码。控制台的代码页是使用 WIN32 API
SetConsoleOutputCP
和 SetConsoleCP
手动设置的,如果您想阅读,则需要手动强制为 UTF8。这需要在执行 exe 的控制台上完成,据我所知,无法从主机的 .NET 环境中完成。
因此,我编写了一个名为 UtfRedirect 的代理应用程序,其源代码已根据 MIT 许可证条款发布在 GitHub 上,旨在在 .NET 主机中生成,然后告诉哪个 exe 执行执行。它将为最终从属 exe 的控制台设置代码页,然后运行它并将标准输出通过管道传输回主机。 UtfRedirector 调用示例:
//At the time of creating the process:
_process = new Process
{
StartInfo =
{
FileName = application,
Arguments = arguments,
RedirectStandardInput = true,
RedirectStandardOutput = true,
StandardOutputEncoding = Encoding.UTF8,
StandardErrorEncoding = Encoding.UTF8,
UseShellExecute = false,
},
};
_process.StartInfo.Arguments = "";
_process.StartInfo.FileName = "UtfRedirect.exe"
//At the time of running the process
_process.Start();
//Write the name of the final slave exe to the stdin of UtfRedirector in UTF8
var bytes = Encoding.UTF8.GetBytes(application);
_process.StandardInput.BaseStream.Write(bytes, 0, bytes.Length);
_process.StandardInput.WriteLine();
//Write the arguments to be sent to the final slave exe to the stdin of UtfRedirector in UTF8
bytes = Encoding.UTF8.GetBytes(arguments);
_process.StandardInput.BaseStream.Write(bytes, 0, bytes.Length);
_process.StandardInput.WriteLine();
//Read the output that has been proxied with a forced codepage of UTF8
string utf8Output = _process.StandardOutput.ReadToEnd();