【问题标题】:How to change the encoding of a Process's Standard Input in C#?如何在 C# 中更改进程标准输入的编码?
【发布时间】:2021-08-13 13:02:09
【问题描述】:

我正在尝试在 C# 中写入进程(C++ 程序)的标准输入。问题是 C++ 程序似乎无法读取我从 C# 应用程序中编写的内容。以下是这两个程序:

// C#
static void Main(string[] args) {
    Console.InputEncoding = Encoding.Unicode;
    Console.OutputEncoding = Encoding.Unicode;

    Process CoutN = new Process();
    CoutN.StartInfo.FileName = @"C:\Users\Vesk\Desktop\CoutN.exe";
    CoutN.StartInfo.UseShellExecute = false;
    CoutN.StartInfo.RedirectStandardInput = true;
    CoutN.StartInfo.RedirectStandardOutput = false;

    CoutN.Start();
    CoutN.StandardInput.WriteLine("5");

    CoutN.WaitForExit();

    Console.ReadKey();
}
// C++
int main() {
    int n;
    std::cin >> n;
    std::cout << "N is " << n << std::endl;
    return 0;
}

这是我的 C# 程序的输出:N is 0。它应该是N is 5

据我所知,C# 用于进程输入/输出流的编码与控制台使用的编码相同。事情是这样的,在我的 C# 程序中,我需要能够使用控制台输入西里尔文文本(以及其他非 ASCII 文本)。唯一似乎适用的控制台编码是Encoding.Unicode(显然只是UTF-16 LE)。

但是当我尝试写入进程的输入流时,它似乎无法理解,并且由于某种原因它输出N is 0。据我了解,这是因为 UTF-16 与 ASCII 不兼容(或 C++ iostream 所期望的)。

那么有没有办法真正改变进程的标准输入使用的编码?

这是我尝试过/不能尝试的:

  • 我不想更改控制台的编码,因为我打算以异步运行的方式运行进程,并且我希望仍然能够与C#程序交互,所以我担心它会搞砸,即使我只是更改编码,也只是在写入进程然后再将其更改回来。
  • 我知道 C++ 程序可能会被更改,以便它可以读取 UTF-16,但我不想这样做,因为我的 C# 程序必须能够运行并与各种“接口” C++ 程序,使用简单的iostreamcincout)。 (编辑澄清:我的 C# 程序只需要向 C++ 程序“发送”ASCII 文本)
  • 我确实尝试将控制台的编码更改为Encoding.ASCII,并且成功了。如果我只是将控制台保留为默认编码,它也可以工作。但这又对我不起作用,因为这些编码似乎不适用于西里尔文。
  • 我尝试将控制台的输入编码设置为Encoding.UTF8,但没有成功,尽管无论如何我都无法使用它,因为它似乎不适用于我的 C# 应用程序中的西里尔文文本。
  • 我尝试更改CoutN.StandardInput.Encoding,但不幸的是它是一个只读属性。
  • 我还尝试重定向标准输出,只是为了看看它是否有效,而且奇怪的是它确实有效。我可以只使用CoutN.StandardOutput.ReadToEnd(),它可以正常工作并且C++程序的输出被正确读取(尽管仍然说N is 0)。但由于某种原因,标准输入有所不同。
  • 我试图不重定向标准输入,再次只是为了看看它是否有效,但又一次非常奇怪的是它成功了!。我刚刚在 C# 程序的控制台中写了5,输出为N is 5
  • 我尝试使用不同的编码创建StreamWriter 并从那里写入:
StreamWriter str = new StreamWriter(CoutN.StandardInput.BaseStream, Encoding.ASCII);
str.WriteLine("5");

但这也不起作用。我什至尝试了基本上所有的编码,甚至没有编码,但没有任何效果。

  • 我尝试自己写信给BaseStream
byte[] buffer = Encoding.ASCII.GetBytes("5");
CoutN.StandardInput.BaseStream.Write(buffer, 0, buffer.Length);
CoutN.StandardInput.WriteLine();

那没有用。

在这一点上,我觉得我已经用尽了所有可以尝试的选项。任何帮助表示赞赏,在此先感谢!

【问题讨论】:

  • STD 输入和输出是流,它们没有编码。当 应用程序 将从流中读取的字节转换为文本时,将应用编码。由于 Windows 是一个 Unicode 操作系统,而 .NET 字符串是 Unicode,所以不应该有任何改变的理由。绝对不要使用甚至无法处理所有英文文本的 7 位 US-ASCII 代码页
  • 问题出在 C++ 代码中,而不是 C#。您正在尝试从标准输入中读取,就好像它包含单字节文本一样。很可能,该程序也被编译为 ASCII 而不是 Unicode。自 1990 年代末、2000 年代初以来,Windows 应用程序以这种方式编译,这正是因为操作系统是 Unicode 并且 Windows 已在全世界范围内使用。虽然在 C++ 中使用 Unicode 很棘手,因为标准化过程非常很慢。虽然现在有 char16_tchar32_tu16stringu32string 类型,但在 C++ 20 之前没有明确的 UTF8 类型。
  • 你所说的 ASCII 是 7 位的 ASCII,它甚至不能处理所有的英文文本,比如Charlotte Brontë。它不被任何操作系统或进程使用。同样,您要问的是如何破坏 C# 程序以避免修复 C++ 错误,这是任何 C++ Windows 应用程序都不应该有的。
  • 与其询问如何更改 C# 编码,不如询问 C++ 编码是什么 - 除非您指定一个,否则它是对应于机器语言环境的那个,不是 ASCII。区域设置中的标签甚至显示Locale used by non-Unicode programs。甚至美国机器也使用 Latin1,而不是 ASCII。这在 C# 程序中显示为 Encoding.Default,因为它就是这样 - 处理非 Unicode I/O 时的默认编码。
  • 长话短说。使用Console.OutputEncoding = Encoding.Default; 甚至完全删除该行。更好的是,修复 C++ 错误。在 Unicode 操作系统上使用 charstring 是完全错误的,这种错误在 2000 年就消失了。

标签: c# c++ input encoding process


【解决方案1】:

您无法从您自己的代码中选择其他进程正在使用的编码 - 如果您将输入发送到期望特定编码的应用程序的标准输入流,那么缺少一些设置改变这一点,你无能为力。

如果您正在与另一个应用程序的 STDIO 流进行交互,您应该匹配它所期望的任何编码,而不是相反。控制台的编码并不重要,除非应用程序从环境中继承其编码。

确实,如果您尝试使用支持西里尔字符的编码,那么接收应用程序的设计必须能够适应这种情况。如果应用程序是由其本地字符集仅使用拉丁字符的人编写的,那么他们很可能从未费心这样做。这是推动在所有地方采用 UTF8 的部分原因,从那时起您真的不需要考虑太多。

编辑:如果您尝试匹配预期的输入编码,那么您可以这样做:

Process.StandardInput.Write(Encoding.ASCII.GetBytes("My String Here\r\n"));

Encoding.ASCII 替换为适用的任何字符集以获得适当的GetBytes() 方法。

请注意,ASCII 字符集特别不包括西里尔字符,因此不可能在需要 ASCII 的应用程序中使用它们。如果它需要一些其他支持它们的字符集,那么你很好。 Cyrillic 使用 Codepage 855 或需要 UTF8。

【讨论】:

  • 也许我在帖子中没有正确解释它,但我确实想匹配 C++ 程序所期望的编码。这就是我想要做的。但我似乎无法找到一种方法来做到这一点,除非在我的 C# 应用程序中更改控制台的编码。此外,我只想/需要将 ASCII 字符发送到我的 C++ 程序。
  • @Vesk 即使在美国也没有 ASCII。如果您想使用与 C++ 应用程序相同的非 Unicode 编码,请使用 Encoding.Default。设置Console.OutputEncoding = Encoding.DefaultEncoding.Default 对应于系统/用户区域设置,在区域设置 GUI 中显示为 Locale used by non-Unicode programs。这就是你的 C++ 应用程序使用的东西
  • @PhonicUK 抱歉,不小心点击了复选标记。
  • 在这种情况下,您可以使用自己的编码直接写入输入流。请参阅我的更新答案。
猜你喜欢
  • 2011-02-13
  • 2012-09-30
  • 2013-02-02
  • 1970-01-01
  • 2021-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多