编码UTF8 C#进程

我有一个处理vbscript并生成输出的应用程序。

private static string processVB(string command, string arguments) { Process Proc = new Process(); Proc.StartInfo.UseShellExecute = false; Proc.StartInfo.RedirectStandardOutput = true; Proc.StartInfo.RedirectStandardError = true; Proc.StartInfo.RedirectStandardInput = true; Proc.StartInfo.StandardOutputEncoding = Encoding.UTF8; Proc.StartInfo.StandardErrorEncoding = Encoding.UTF8; Proc.StartInfo.FileName = command; Proc.StartInfo.Arguments = arguments; Proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; //prevent console window from popping up Proc.Start(); string output = Proc.StandardOutput.ReadToEnd(); string error = Proc.StandardError.ReadToEnd(); if (String.IsNullOrEmpty(output) && !String.IsNullOrEmpty(error)) { output = error; } //Console.Write(ping_output); Proc.WaitForExit(); Proc.Close(); return output; } 

我想我已经设置了与Encoding属性相关的所有内容。 processVB方法将获取命令作为VBscript文件及其参数。

C#方法processVB正在处理VBScript文件现在产生如下输出。

“?”

但我应该得到原始文本

“äåéö€”

我已正确设置编码。 但我无法做到对。

我究竟做错了什么?

这个答案并没有回答直接的问题 – 但我注意到你的代码中存在死锁的可能性,因此无论如何都认为发布它是值得的。

由于您的代码尝试从重定向输出执行同步读取,并且为StdOut和StdErr执行同步读取,因此存在死锁可能性。 即代码的这一部分。

 Proc.Start(); string output = Proc.StandardOutput.ReadToEnd(); string error = Proc.StandardError.ReadToEnd(); ... Proc.WaitForExit(); 

可能发生的是子进程将大量数据写入StdErr并填充缓冲区。 一旦缓冲区被填满,子进程将阻止写入StdErr(没有发出StdOut流的结束信号)。 所以孩子被阻止而没有做任何事情,你的过程被阻止等待孩子退出。 僵局!!!

要解决此问题,应将至少一个(或更好的两个)流切换到异步模式。

请参阅MSDN中的第二个示例,该示例专门讨论此案例场景,以及如何切换到异步模式。

至于UTF-8问题,您确定您的子进程是以这种编码输出而不是用UTF-16或其他一些进行输出吗? 您可能需要检查字节以尝试撤消提供的编码流,以便您可以设置正确的编码来解释重定向的流。

编辑

以下是我认为您可以解决编码问题的方法。 基本的想法是基于我曾经需要做的事情 – 我有未知编码的俄语文本,并需要弄清楚如何转换它以显示正确的字符 – 从StdOut捕获的字节,并尝试使用它们解码它们系统上可用的所有已知代码页。 看起来正确的那个可能(但不一定)是StdOut编码的编码。 即使它与您的数据看起来正确也不能保证它是一个原因是因为许多编码在某些字节范围内重叠会使其工作相同。 例如,ASCII和UTF8在编码基本拉丁字符时将具有相同的字节。 因此,为了获得完全匹配,您可能需要创造性并使用一些非典型文本进行测试。

以下是执行此操作的基本代码 – 可能需要进行调整:

  byte[] text =  foreach(System.Text.EncodingInfo encodingInfo in System.Text.Encoding.GetEncodings()) { System.Text.Encoding encoding = encodingInfo.GetEncoding(); string decodedBytes = encoding.GetString(bytes); System.Console.Out.WriteLine("Encoding: {0}, Decoded Bytes: {1}", encoding.EncodingName, decodedBytes); } 

运行代码并手动检查输出。 与预期文本匹配的所有内容都是StdOut中使用的编码的候选者。

问题是默认情况下控制台不是UTF-8。 它与Windows中的区域设置在同一代码页中运行。 解决此问题的一种简单方法是使用chcp console命令。 例:

 chcp 65001 && yourScript.vbs 

这将导致输出为UTF-8,并确保您可以从.NET应用程序中正确读取它。

请注意,我用bat脚本而不是VB脚本测试了这个,但是如果VB脚本支持UTF-8,它应该可以正常工作。 此外,您可能必须显式调用VB脚本执行引擎而不仅仅是yourScript.vbs 。 但你应该能够自己解决这个问题:)

因为VBScript生成的输出是UTF8

这是让你在这里遇到麻烦的假设,它不是utf-8。 也不是,脚本引擎不支持设置它。 您可以自己尝试的东西,在示例.vbs文件中使用此语句:

  SetLocale 65001 

Kaboom,它只接受LCID值,它们不包括utf编码。 相反,cscript.exe脚本引擎已经更改了默认代码页本身。 它将切换到默认的Windows代码页,而不是默认的OEM代码页(HKEY_LOCAL_MACHINE \ SYSTEM \ ControlSet \ Control \ Nls \ CodePage \ OEMCP值)。 上述文档注册表项中的ACP值。 取决于您的位置,例如在美洲和西欧将是1252。

要使用的一些VBScript代码,请确保使用适合您的语言环境的默认编码保存文件,否则脚本解释器本身将错误地解释源代码中的字符串。 这本身也可以解释你的问题:

 WScript.Echo "Locale: " & GetLocale WScript.Echo "äåéö€" WScript.Echo "Changing locale to US-English:" SetLocale 1033 WScript.Echo "äåéö€" 

我机器上的输出:

 C:\temp>cscript test.vbs Microsoft (R) Windows Script Host Version 5.8 Copyright (C) Microsoft Corporation. All rights reserved. Locale: 1033 äåéö€ Changing locale to US-English: äåéö€ 

因此,程序中的正确代码行应为:

 Proc.StartInfo.StandardOutputEncoding = Encoding.Default; 

请注意,这不是 Process类使用的默认值,它将假定控制台模式程序使用OEM代码页。 就像437在北美和西欧的机器上一样。 您可以在.vbs程序中选择另一个LCID并更改您的C#代码以匹配,但这不是必需的。

并且确保将.vbs源代码文件编码错误的故障模式保持不变。 不幸的是,脚本引擎也不支持带有BOM的utf-8。

另一个进程(vbscript)以某种编码方式生成并输出。 通过设置StandardOutputEncoding,您可以告诉系统如何读取该流。 这不会更改其他进程的编码。

因此,您需要确定其他进程(VBScript)使用的确切编码。 为此我直接从shell运行脚本并将输出重定向到文件并在显示编码的工具中打开它(即notepad2)如果我是对的,那将是UTF8以外的东西。

然后在代码中将Proc.StartInfo.StandardOutputEncoding设置为该编码,然后一切都应该工作。

我正在使用你的function:

 label1.Text = processVB("wscript.exe", "c:\\s.vbs"); 

我的vbs文件是

 Set fso = CreateObject ("Scripting.FileSystemObject") Set stdout = fso.GetStandardStream (1) stdout.WriteLine "äåéö€" 

我的vbs文件编码为UTF-8,没有BOM

它按预期工作。 我在表格上看到了äåéö€

也许您应该改变使用函数的方式,vbs文件的编码以及如何将数据输出到stdout。