编码UTF8 c#进程
本文关键字:进程 UTF8 编码 | 更新日期: 2023-09-27 17:50:15
我有一个处理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;
}
我想我已经设置了与编码属性正确相关的一切。processVB方法将获取命令作为VBscript文件及其参数。
正在处理VBScript文件的c#方法processVB现在产生如下输出:
"����?"
但是我应该得到原始文本
" aaeo€"
我已经正确设置了编码。但是我做不好。
我做错了什么?
这个答案不是直接回答问题-但我注意到你的代码中有死锁的可能性,因此认为无论如何都值得发布。
由于您的代码试图从重定向输出中同步读取,并且对StdOut和StdErr都执行此操作,因此存在死锁的可能性。即这一段代码。
Proc.Start();
string output = Proc.StandardOutput.ReadToEnd();
string error = Proc.StandardError.ReadToEnd();
...
Proc.WaitForExit();
可能发生的情况是子进程向StdErr写入大量数据并填满缓冲区。一旦缓冲区被填满,子进程将阻塞写入标准输出(StdOut流尚未结束)。所以child被阻塞了,什么都不做,你的进程被阻塞了,等待child退出。死锁! !
要解决这个问题,至少一个(最好两个)流应该切换到异步模式。
请参阅MSDN中的第二个示例,该示例专门讨论了这种情况,以及如何切换到异步模式。
对于UTF-8
问题,您确定子进程以这种编码输出,而不是以UTF-16
或其他编码输出吗?您可能需要检查字节,以尝试反转提供的编码流,以便您可以设置正确的编码来解释重定向流。
编辑
这是我认为你可以如何解决编码问题。基本思想是基于我曾经需要做的事情—我有未知编码的俄语文本,并且需要弄清楚如何转换它以显示正确的字符—从StdOut捕获字节,并尝试使用系统上可用的所有已知代码页对它们进行解码。看起来正确的编码可能(但不一定)是StdOut编码使用的编码。即使它与您的数据看起来正确,也不能保证它是正确的原因是因为许多编码在某些字节范围上有重叠,这将使其工作相同。例如,ASCII和UTF8在编码基本拉丁字符时具有相同的字节。因此,为了获得精确匹配,您可能需要创造性地使用一些非典型文本进行测试。
下面是基本代码——可能需要进行调整:
byte[] text = <put here bytes captured from StandardOut of child process>
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);
}
运行代码并手动检查输出。所有与预期文本匹配的编码都是标准输出中使用的候选编码。
问题是控制台默认不是UTF-8。它运行在与Windows中的区域设置相同的代码页中。解决这个问题的一个简单方法是使用chcp
控制台命令。例子:
chcp 65001 && yourScript.vbs
这将导致输出为UTF-8格式,并确保您可以从。net应用程序中正确地读取它。
请注意,我已经用bat
脚本而不是VB-script进行了测试,但是如果VB-script确实支持UTF-8,它应该工作得很好。此外,您可能必须显式调用VB-script执行引擎,而不仅仅是yourScript.vbs
。但是您应该能够自己轻松地解决这个问题:)
因为VBScript生成的输出是UTF8
这就是让你陷入麻烦的假设,它不是utf-8。也不可能,脚本引擎不支持设置它。您可以自己尝试一下,在样例.vbs文件中使用以下语句:
SetLocale 65001
Kaboom,它只接受LCID值,它们不包括utf编码。相反,cscript.exe脚本引擎已经更改了默认代码页本身。而不是默认的OEM代码页(HKEY_LOCAL_MACHINE'SYSTEM'ControlSet'Control'Nls'CodePage'OEMCP值),它切换到默认的Windows代码页。上述记录的注册表项中的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。
Checkout this this answer
可能也与过程输出有关....
另一个进程(vbscript)生成并输出一些编码。通过设置StandardOutputEncoding,您可以告诉系统如何读取该流。这不会改变其他进程所做的编码。
所以你需要弄清楚其他进程(VBScript)使用的确切编码。为此,我会直接从shell运行脚本,并将输出重定向到一个文件,并在显示编码(即notepad2)的工具中打开它,如果我是对的,那将是UTF8以外的东西。
然后将Proc.StartInfo.StandardOutputEncoding设置为代码中的编码,然后一切都应该工作。
我像这样使用你的函数:
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的方式。