如何从 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 文件的编码。

获取控制台的编码。

  • Get 映射到编码的标识符

  • 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文件,内容根据需要保存。