如何从 c# 中的 robocopy 过程标准输出中获取 unicode 字符
How can I get unicode characters from robocopy process standard ouput in c#
我们的应用程序运行各种操作并在日志中显示输出 window。一项操作使用 robocopy 在文件夹之间复制文件。
在 robocopy 输出包含 unicode 字符之前,这一切正常。我知道我需要使用 /unicode 选项,但我似乎得到的只是乱码。
这是我的简化代码示例:
class Program
{
static void Main(string[] args)
{
StreamReader outputReader = null;
StreamReader errorReader = null;
using (Process process = new Process())
{
Encoding encoding = Encoding.Default;
if (encoding != null)
{
process.StartInfo.StandardOutputEncoding = encoding;
process.StartInfo.StandardErrorEncoding = encoding;
}
process.StartInfo.FileName = @"C:\Windows\system32\robocopy.exe";
process.StartInfo.Arguments = @"""D:\temp\некоторые случайные папки"" ""D:\temp\другой случайные папки"" /unicode";
process.StartInfo.ErrorDialog = false;
process.StartInfo.LoadUserProfile = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WorkingDirectory = @"D:\temp\некоторые случайные папки";
bool processStarted = process.Start();
if (processStarted)
{
//Get the output stream
outputReader = process.StandardOutput;
errorReader = process.StandardError;
process.WaitForExit();
string standardOutput = outputReader.ReadToEnd();
string errorOutput = errorReader.ReadToEnd();
if (!string.IsNullOrEmpty(standardOutput))
{
byte[] bytes = encoding.GetBytes(standardOutput);
byte[] convertedBytes = Encoding.Convert(encoding, Encoding.UTF8, bytes);
string convertedStandardOutput = Encoding.UTF8.GetString(convertedBytes);
Console.Write("Standard output: ");
Console.WriteLine(convertedStandardOutput);
}
if (!string.IsNullOrEmpty(errorOutput))
{
Console.Write("Error output: ");
Console.WriteLine(errorOutput);
}
}
}
Console.ReadKey();
}
}
我试过各种编码类型和转换都无济于事。这是我得到的输出类型:
standardOutput: "ⴊⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭ †佒佂佃奐††㨠›††潒畢瑳䘠汩潃祰映牯圠湩潤獷†††††††††††††††ⴊⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭਊ†瑓牡整›潍摮祡㘱䴠牡档㈠‵㐱ㄺ㨵㈵ †潓牵散㨠䐠尺整灭㽜㼿㼿㼿㼿㼠㼿㼿㼿㼿㼠㼿㼿ੜ††䐠獥⁴›㩄瑜浥屰㼿㼿㼿㼠㼿㼿㼿㼿㼠㼿㼿ੜ †䘠汩獥㨠⨠⨮ऊ†† 传瑰潩獮㨠⨠⸀⨀ ⼀唀一䤀䌀伀䐀䔀 ⼀䐀䌀伀倀夀㨀䐀䄀 ⼀䌀伀倀夀㨀䐀䄀吀 ⼀刀㨀 ⼀圀㨀㌀ ⴊⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭਭऊ†††††††††〠䐉尺整灭㽜㼿㼿㼿㼿㼠㼿㼿㼿㼿㼠㼿㼿ੜⴊⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭਭ †††††††潔慴†䌠灯敩†歓灩数䴠獩慭捴†䘠䥁䕌⁄†䔠瑸慲ੳ††楄獲㨠††††ㄠ††††〠††††〠††††〠††††〠††††〠 †楆敬›††††‰††††‰††††‰††††‰††††‰††††ਰ†䈠瑹獥㨠††††〠††††〠††††〠††††〠††††〠††††〠 †楔敭›†㨰〰〺‰†㨰〰〺‰†††††††††††㨰〰〺‰†㨰〰〺ਰ†䔠摮摥㨠䴠湯慤ⱹㄠ‶慍捲〲㔱ㄠ㨴㔱㔺ਲ"
convertedStandardOutput: "?????????????????????????????????????????†????††?›††??????????????†††††††††††††††?????????????????????????????????????????†????›??????????`?????†??????????????????????††??4›?????????????????†???????††????????? ???????? ????????? ????????? ???? ???? ??????????????????????????????????????????†††††††††????????????????????????????????????????????????????????????†††††††???†????†?????????†???/†????††???††††?††††?††††?††††?††††?††††??†???›††††‰††††‰††††‰††††‰††††‰††††?†????††††?††††?††††?††††?††††?††††??†???›†???‰†???‰†††††††††††???‰†????†????????????????????"
命令window中运行时显示的输出为:
■
---------------------------------------------- ------------------------------
ROBOCOPY :: Windows 的强大文件复制
---------------------------------------------- ------------------------------
开始时间:2015 年 3 月 16 日,星期一 14:24:01
来源:D:\temp\некоторые случайные папки\
目的地:D:\temp\другойслучайныепапки\
文件:*.*
选项 : * 。 * / U N I C O D E / D C O P Y : D A / C O P Y : D A T / R : 1 0 0 0 0 0 0 / W : 3 0
---------------------------------------------- ----------------------------
0 D:\temp\некоторые случайные папки\
---------------------------------------------- ----------------------------
Total Copied Skipped Mismatch FAILED 额外
目录:1 0 0 0 0 0
文件:0 0 0 0 0 0
字节:0 0 0 0 0 0
次 : 0:00:00 0:00:00 0:00:00 0:00:00
结束时间:2015 年 3 月 16 日,星期一 14:24:01
有什么想法吗?
让我先说明一下 post..我不是 C# 开发人员,但我了解文件编码。
你的文件有一个编码,你的控制台有一个标准输入和标准输出的编码。 C# 在其运行时对其字符串进行编码。编码是符号到位的映射。 Unicode 是一种统一许多不同类型编码的尝试,blah blah
暂时忽略robocop,然后想办法让控制台正确打印。
Get 文件的编码。
获取控制台的编码。
现在剩下的就是在写入 stdout 之前将文件的编码转换为控制台期望的编码。
提示:您的控制台日志可以正常显示 Unicode 字符。我的猜测是该文件具有 UTF-16,而您的控制台需要 UTF-8。
看起来 /UNICODE 选项有问题:它在控制台输出中唯一影响的是 Options :
行。 (你可以从字符之间的空格看出这部分是 Unicode,这是由额外的空字节引起的。)ROBOCOPY 似乎仍然使用系统代码页编写其他所有内容。但是 /UNICODE 选项 确实 导致 ROBOCOPY 在输出的开头写出 Unicode 字节顺序标记,因此无论您设置什么 StandardOutputEncoding,StreamReader 都会切换到 Unicode。结果:乱码。
使用 /UNILOG 选项代替 /UNICODE,它似乎可以正常工作(至少在 Windows 8.1 上):
using (Process process = new Process())
{
string logFileName = Path.GetTempFileName();
process.StartInfo.FileName = @"C:\Windows\system32\robocopy.exe";
process.StartInfo.Arguments = @"""D:\temp\некоторые случайные папки"" ""D:\temp\другой случайные папки"" /UNILOG:" + logFileName;
process.StartInfo.ErrorDialog = false;
process.StartInfo.LoadUserProfile = false;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WorkingDirectory = @"D:\temp\некоторые случайные папки";
bool processStarted = process.Start();
if (processStarted)
{
process.WaitForExit();
string output = File.ReadAllText(logFileName);
File.Delete(logFileName);
// TODO: Do something with the output.
}
}
您可以只创建一个 ANSI 空白文件,而不是 robocopy 在 header...
使用Notepad++找出文件编码。
我在 this Super User answer by Karan 中找到了解决方法:
If your file or directory names contain Unicode characters then before
issuing the Robocopy command with the /unilog parameter use the
chcp 65001 command.
Once you have the mangled Unicode log, just open it up in MS Word as
Unicode (UTF-8) and save it:
显然,您可以编写自己的代码以 UTF-8 格式读取文件,而不是使用 MS word。
我在 win 8.1 和 win10 上使用 /unilog+ 键时遇到问题。当只使用 /unilog(没有加号)时,带有西里尔文的文件通常被写入日志文件,而使用 unilog+ 已经是乱码了。这是 robocopy 本身的一个恼人的错误:事实证明 /unilog+ 只是创建一个日志文件作为 ANSI。解决问题的方法之一是先为日志创建一个utf-8或unicode编码的文件,并在key中指定文件名。然后将日志写入一个unicode文件,内容根据需要保存。
我们的应用程序运行各种操作并在日志中显示输出 window。一项操作使用 robocopy 在文件夹之间复制文件。
在 robocopy 输出包含 unicode 字符之前,这一切正常。我知道我需要使用 /unicode 选项,但我似乎得到的只是乱码。
这是我的简化代码示例:
class Program
{
static void Main(string[] args)
{
StreamReader outputReader = null;
StreamReader errorReader = null;
using (Process process = new Process())
{
Encoding encoding = Encoding.Default;
if (encoding != null)
{
process.StartInfo.StandardOutputEncoding = encoding;
process.StartInfo.StandardErrorEncoding = encoding;
}
process.StartInfo.FileName = @"C:\Windows\system32\robocopy.exe";
process.StartInfo.Arguments = @"""D:\temp\некоторые случайные папки"" ""D:\temp\другой случайные папки"" /unicode";
process.StartInfo.ErrorDialog = false;
process.StartInfo.LoadUserProfile = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WorkingDirectory = @"D:\temp\некоторые случайные папки";
bool processStarted = process.Start();
if (processStarted)
{
//Get the output stream
outputReader = process.StandardOutput;
errorReader = process.StandardError;
process.WaitForExit();
string standardOutput = outputReader.ReadToEnd();
string errorOutput = errorReader.ReadToEnd();
if (!string.IsNullOrEmpty(standardOutput))
{
byte[] bytes = encoding.GetBytes(standardOutput);
byte[] convertedBytes = Encoding.Convert(encoding, Encoding.UTF8, bytes);
string convertedStandardOutput = Encoding.UTF8.GetString(convertedBytes);
Console.Write("Standard output: ");
Console.WriteLine(convertedStandardOutput);
}
if (!string.IsNullOrEmpty(errorOutput))
{
Console.Write("Error output: ");
Console.WriteLine(errorOutput);
}
}
}
Console.ReadKey();
}
}
我试过各种编码类型和转换都无济于事。这是我得到的输出类型:
standardOutput: "ⴊⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭ †佒佂佃奐††㨠›††潒畢瑳䘠汩潃祰映牯圠湩潤獷†††††††††††††††ⴊⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭਊ†瑓牡整›潍摮祡㘱䴠牡档㈠‵㐱ㄺ㨵㈵ †潓牵散㨠䐠尺整灭㽜㼿㼿㼿㼿㼠㼿㼿㼿㼿㼠㼿㼿ੜ††䐠獥⁴›㩄瑜浥屰㼿㼿㼿㼠㼿㼿㼿㼿㼠㼿㼿ੜ †䘠汩獥㨠⨠⨮ऊ†† 传瑰潩獮㨠⨠⸀⨀ ⼀唀一䤀䌀伀䐀䔀 ⼀䐀䌀伀倀夀㨀䐀䄀 ⼀䌀伀倀夀㨀䐀䄀吀 ⼀刀㨀 ⼀圀㨀㌀ ⴊⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭਭऊ†††††††††〠䐉尺整灭㽜㼿㼿㼿㼿㼠㼿㼿㼿㼿㼠㼿㼿ੜⴊⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭⴭਭ †††††††潔慴†䌠灯敩†歓灩数䴠獩慭捴†䘠䥁䕌⁄†䔠瑸慲ੳ††楄獲㨠††††ㄠ††††〠††††〠††††〠††††〠††††〠 †楆敬›††††‰††††‰††††‰††††‰††††‰††††ਰ†䈠瑹獥㨠††††〠††††〠††††〠††††〠††††〠††††〠 †楔敭›†㨰〰〺‰†㨰〰〺‰†††††††††††㨰〰〺‰†㨰〰〺ਰ†䔠摮摥㨠䴠湯慤ⱹㄠ‶慍捲〲㔱ㄠ㨴㔱㔺ਲ"
convertedStandardOutput: "?????????????????????????????????????????†????††?›††??????????????†††††††††††††††?????????????????????????????????????????†????›??????????`?????†??????????????????????††??4›?????????????????†???????††????????? ???????? ????????? ????????? ???? ???? ??????????????????????????????????????????†††††††††????????????????????????????????????????????????????????????†††††††???†????†?????????†???/†????††???††††?††††?††††?††††?††††?††††??†???›††††‰††††‰††††‰††††‰††††‰††††?†????††††?††††?††††?††††?††††?††††??†???›†???‰†???‰†††††††††††???‰†????†????????????????????"
命令window中运行时显示的输出为:
■ ---------------------------------------------- ------------------------------ ROBOCOPY :: Windows 的强大文件复制 ---------------------------------------------- ------------------------------ 开始时间:2015 年 3 月 16 日,星期一 14:24:01 来源:D:\temp\некоторые случайные папки\ 目的地:D:\temp\другойслучайныепапки\ 文件:*.* 选项 : * 。 * / U N I C O D E / D C O P Y : D A / C O P Y : D A T / R : 1 0 0 0 0 0 0 / W : 3 0 ---------------------------------------------- ---------------------------- 0 D:\temp\некоторые случайные папки\ ---------------------------------------------- ---------------------------- Total Copied Skipped Mismatch FAILED 额外 目录:1 0 0 0 0 0 文件:0 0 0 0 0 0 字节:0 0 0 0 0 0 次 : 0:00:00 0:00:00 0:00:00 0:00:00 结束时间:2015 年 3 月 16 日,星期一 14:24:01
有什么想法吗?
让我先说明一下 post..我不是 C# 开发人员,但我了解文件编码。
你的文件有一个编码,你的控制台有一个标准输入和标准输出的编码。 C# 在其运行时对其字符串进行编码。编码是符号到位的映射。 Unicode 是一种统一许多不同类型编码的尝试,blah blah
暂时忽略robocop,然后想办法让控制台正确打印。
Get 文件的编码。
获取控制台的编码。
现在剩下的就是在写入 stdout 之前将文件的编码转换为控制台期望的编码。
提示:您的控制台日志可以正常显示 Unicode 字符。我的猜测是该文件具有 UTF-16,而您的控制台需要 UTF-8。
看起来 /UNICODE 选项有问题:它在控制台输出中唯一影响的是 Options :
行。 (你可以从字符之间的空格看出这部分是 Unicode,这是由额外的空字节引起的。)ROBOCOPY 似乎仍然使用系统代码页编写其他所有内容。但是 /UNICODE 选项 确实 导致 ROBOCOPY 在输出的开头写出 Unicode 字节顺序标记,因此无论您设置什么 StandardOutputEncoding,StreamReader 都会切换到 Unicode。结果:乱码。
使用 /UNILOG 选项代替 /UNICODE,它似乎可以正常工作(至少在 Windows 8.1 上):
using (Process process = new Process())
{
string logFileName = Path.GetTempFileName();
process.StartInfo.FileName = @"C:\Windows\system32\robocopy.exe";
process.StartInfo.Arguments = @"""D:\temp\некоторые случайные папки"" ""D:\temp\другой случайные папки"" /UNILOG:" + logFileName;
process.StartInfo.ErrorDialog = false;
process.StartInfo.LoadUserProfile = false;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WorkingDirectory = @"D:\temp\некоторые случайные папки";
bool processStarted = process.Start();
if (processStarted)
{
process.WaitForExit();
string output = File.ReadAllText(logFileName);
File.Delete(logFileName);
// TODO: Do something with the output.
}
}
您可以只创建一个 ANSI 空白文件,而不是 robocopy 在 header... 使用Notepad++找出文件编码。
我在 this Super User answer by Karan 中找到了解决方法:
If your file or directory names contain Unicode characters then before issuing the Robocopy command with the /unilog parameter use the chcp 65001 command.
Once you have the mangled Unicode log, just open it up in MS Word as Unicode (UTF-8) and save it:
显然,您可以编写自己的代码以 UTF-8 格式读取文件,而不是使用 MS word。
我在 win 8.1 和 win10 上使用 /unilog+ 键时遇到问题。当只使用 /unilog(没有加号)时,带有西里尔文的文件通常被写入日志文件,而使用 unilog+ 已经是乱码了。这是 robocopy 本身的一个恼人的错误:事实证明 /unilog+ 只是创建一个日志文件作为 ANSI。解决问题的方法之一是先为日志创建一个utf-8或unicode编码的文件,并在key中指定文件名。然后将日志写入一个unicode文件,内容根据需要保存。