Process.StandardInput 或从 C# 代码执行的应用程序的编码问题

发布于 2024-09-01 13:43:36 字数 770 浏览 5 评论 0原文

我在 Process.StandartInput 编码方面遇到问题。我在 Windows 窗体应用程序中使用一些进程,但输入应该是 UTF-8。 Process.StandardInput.Encoding 是只读的,因此我无法将其设置为 UTF-8,并且它会获取 Windows 默认编码,这会恶化 UTF-8 中良好的本机字符。程序中使用了两个进程:一个将输出写入文件,另一个进行读取。由于我可以将输出编码设置为 UTF-8,该部分工作正常,但回读是我遇到问题的部分。我将包括我使用该过程的部分。

ProcessStartInfo info = new ProcessStartInfo("mysql");
info.RedirectStandardInput = true;
info.RedirectStandardOutput = false;
info.Arguments = mysqldumpstring;
info.UseShellExecute = false;
info.CreateNoWindow = true;
Process p1 = new Process();
p1.StartInfo = info;
p1.Start();
string res = file.ReadToEnd();
file.Close();

// where encoding should be Encoding.UTF8;
MessageBox.Show(p1.StandardInput.Encoding.EncodingName); 

p1.StandardInput.WriteLine(res);
p1.Close(); 

I have an issue with encoding of Process.StandartInput encoding. I am using some process in my Windows Form application but input should be UTF-8. Process.StandardInput.Encoding is read only so I can't set it to UTF-8 and it gets Windows default encoding which deteriorate native characters which are good in UTF-8. Two processes are used in the program: one writes output to a file and other reads. Since I can set up output encoding to UTF-8 that part is working properly but reading back is the part where I am having problems. I'll include the part where I use the process.

ProcessStartInfo info = new ProcessStartInfo("mysql");
info.RedirectStandardInput = true;
info.RedirectStandardOutput = false;
info.Arguments = mysqldumpstring;
info.UseShellExecute = false;
info.CreateNoWindow = true;
Process p1 = new Process();
p1.StartInfo = info;
p1.Start();
string res = file.ReadToEnd();
file.Close();

// where encoding should be Encoding.UTF8;
MessageBox.Show(p1.StandardInput.Encoding.EncodingName); 

p1.StandardInput.WriteLine(res);
p1.Close(); 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

归途 2024-09-08 13:43:36

使用 StreamWriter 创建的下一种方式(而不是 StandardInput)给出了所需的结果:

StreamWriter utf8Writer = new StreamWriter(proc.StandardInput.BaseStream, Encoding.UTF8);
utf8Writer.Write(...);
utf8Writer.Close();

Using of StreamWriter created the next way (instead of StandardInput) gives desired result:

StreamWriter utf8Writer = new StreamWriter(proc.StandardInput.BaseStream, Encoding.UTF8);
utf8Writer.Write(...);
utf8Writer.Close();
谁的年少不轻狂 2024-09-08 13:43:36

我刚刚遇到这个问题,无法使用 Console.InputEncoding 技术,因为它似乎只适用于控制台应用程序。

因此,我尝试了 Victor 的答案,但是我遇到了与评论者 MvanGeest 相同的问题,其中 BOM 仍在添加。一段时间后,我发现可以创建一个禁用 BOM 的新 UTF8Encoding 实例,这样做会阻止 BOM 被写入。这是 Victor 示例的修改版本,显示了更改。

StreamWriter utf8Writer = new StreamWriter(proc.StandardInput.BaseStream, new UTF8Encoding(false));
utf8Writer.Write(...);
utf8Writer.Close();

希望这可以节省一些人的时间。

I've just encountered this problem and was unable to use the Console.InputEncoding technique because it only seems to work in console applications.

Because of this I tried Victor's answer, however I encountered the same issue as the commenter MvanGeest where by the BOM was still being added. After a while I discovered that it is possible to create a new instance of UTF8Encoding that has the BOM disabled, doing this stops the BOM from being written. Here is a modified version of Victor's example showing the change.

StreamWriter utf8Writer = new StreamWriter(proc.StandardInput.BaseStream, new UTF8Encoding(false));
utf8Writer.Write(...);
utf8Writer.Close();

Hope this saves someone some time.

冰葑 2024-09-08 13:43:36

另一个解决方案是设置 Console.InputEncoding在创建流程之前。

 Console.InputEncoding = new UTF8Encoding(false);

Another solution is to set the Console.InputEncoding before you create the process.

 Console.InputEncoding = new UTF8Encoding(false);
你是我的挚爱i 2024-09-08 13:43:36

现在让它工作,将我的应用程序输出类型设置为控制台应用程序,并设法隐藏出现在表单之前的控制台窗口。仅当程序运行时,它基本上才像正常情况一样工作,控制台窗口会弹出并隐藏。

static class Program
{
    [DllImport("kernel32.dll")]
    static extern bool AttachConsole(int dwProcessId);
    private const int ATTACH_PARENT_PROCESS = -1;

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool SetConsoleCP(
         uint wCodePageID
         );

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern uint GetConsoleCP();

    [DllImport("user32.dll")]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll")]
    static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Console.Title = "Stok";
        // redirect console output to parent process;
        // must be before any calls to Console.WriteLine()
        AttachConsole(ATTACH_PARENT_PROCESS);
        System.Console.InputEncoding = Encoding.UTF8;

        IntPtr hWnd = FindWindow(null, "Stok"); //put your console window caption here

        if (hWnd != IntPtr.Zero)
        {
            //Hide the window
            ShowWindow(hWnd, 0); // 0 = SW_HIDE
        }

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
}

got it working now set my application output type to console application and managed to hide the console window appears before the forms. It basically works like normal only when program run, a console windows pops and hides.

static class Program
{
    [DllImport("kernel32.dll")]
    static extern bool AttachConsole(int dwProcessId);
    private const int ATTACH_PARENT_PROCESS = -1;

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool SetConsoleCP(
         uint wCodePageID
         );

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern uint GetConsoleCP();

    [DllImport("user32.dll")]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll")]
    static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Console.Title = "Stok";
        // redirect console output to parent process;
        // must be before any calls to Console.WriteLine()
        AttachConsole(ATTACH_PARENT_PROCESS);
        System.Console.InputEncoding = Encoding.UTF8;

        IntPtr hWnd = FindWindow(null, "Stok"); //put your console window caption here

        if (hWnd != IntPtr.Zero)
        {
            //Hide the window
            ShowWindow(hWnd, 0); // 0 = SW_HIDE
        }

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
}
呆萌少年 2024-09-08 13:43:36

将 StandardInput 发送到“cmd.exe”时,我遇到了各种编码问题。我正在生成一个批处理文件,该文件使用 mklink 和各种非 ASCII 文件名。

我得出的结论是,将 StandardInput.BaseStream 包装在 UTF8 StreamWriter 中无法正常工作(至少对于 cmd.exe 和我拥有的文件名)。更改编码修复了一些问题,但随后又破坏了其他问题。

这对我有用:

  • 将批处理文件保存为 UTF8 无 BOM 的临时文件,如下所示: File.WriteAllText("temp.bat", batchText, new UTF8Encoding(false));
  • 将 StandardOutputEncoding 和 StandardErrorEncoding 设置为 Encoding.UTF8
  • 发送到 StandardInput 2 行:“chcp 65001”+Environment.NewLine +“temp.bat”+Environment.NewLine

这仅适用于命令“chcp 65001”告诉的“cmd.exe”它使用UTF8。

忘记 StandardInput 编码,发送的 2 行都是 ASCII

I had various encoding problems when sending StandardInput to "cmd.exe". I was generating a batch file that used mklink with various non ASCII filenames.

I came to the conclusion that wrapping StandardInput.BaseStream in a UTF8 StreamWriter does not work properly (at least with cmd.exe and the filenames I had). Changing encoding fixed some but then broke others.

This is what worked for me:

  • Save batch file to a temporary file as UTF8 no BOM, like so: File.WriteAllText("temp.bat", batchText, new UTF8Encoding(false));
  • Set StandardOutputEncoding and StandardErrorEncoding to Encoding.UTF8
  • Sent to StandardInput the 2 lines: "chcp 65001" + Environment.NewLine + "temp.bat" + Environment.NewLine

This is only good for "cmd.exe" the command "chcp 65001" tells it to use UTF8.

Forget about StandardInput encoding the 2 lines being sent are ASCII

|煩躁 2024-09-08 13:43:36

事实上,现在有很多更好的方法可以做到这一点。您可以从一开始就为原始编写器配置编码,而不是包装到额外的编写器中:

Process.Start(new ProcessStartInfo("mysql")
{
    UseShellExecute = false,
    RedirectStandardInput = true,
    StandardInputEncoding = new UTF8Encoding(false),
});

另外,请注意 Encoding.UTF8 可能会发出 BOM,因此,与默认的 StreamWriter 类似构造函数中,创建 new UTF8Encoding(false) 来禁用 BOM 总是一个好主意(并且您可以将其缓存在静态字段中,类似于 MS 内部所做的事情)

此外 Nick Randell 的答案也被低估了,它确实有效(只要你也可以在全球范围内为你的流程拥有它)。但在“大企业”中,这不是很好的解决方案,不同的团队可能会在默认情况下发生冲突。

Actually there is a lot better way to do so nowadays. Instead of wrapping into extra writer, you can configure Encoding for original one from the very beginning:

Process.Start(new ProcessStartInfo("mysql")
{
    UseShellExecute = false,
    RedirectStandardInput = true,
    StandardInputEncoding = new UTF8Encoding(false),
});

Also, note that Encoding.UTF8 might emit BOM, so, similarly to default StreamWriter constructor, it is always a good idea to create new UTF8Encoding(false) to disable BOM (and you can cache it in static field, similarly to what MS are doing internally)

Also Nick Randell's answer is underestimated, it works indeed (as long as you are fine to have it globally for your process as well). But in "Big Enterprise" this is not very good solution, different teams might get into conflict on what should be by default.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文