子プロセスの標準ストリームとして取得できるオブジェクトはStreamWriter/StreamReaderであるため、バイナリ形式での読み書きには向いていません。 また、非同期読み込みでのイベント引数DataReceivedEventArgsも文字列型(≒テキスト形式)として受信されるようになっています。
子プロセスの標準ストリームに対してバイナリ形式の読み書きを行う場合は、まず標準ストリームのStreamWriter/StreamReaderからBaseStreamプロパティを参照することにより、標準ストリームのStreamを取得します。
次に、BaseStreamプロパティから取得したStreamに対して直接読み書きを行うか、StreamからBinaryWriter/BinaryReaderなどを作成して読み書きすることにより、標準ストリームでバイナリ形式のデータを扱うことができるようになります。
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
class Sample {
static void Main()
{
// 子プロセスchild.exeの起動オプション
var psi = new ProcessStartInfo("child.exe") {
// シェルを使用せず子プロセスを起動する
// (リダイレクトするために必要)
// ⚠.NET Core/.NET 5以降ではデフォルトでfalseとなっている
UseShellExecute = false,
// 起動した子プロセスの標準入出力をリダイレクトする
RedirectStandardInput = true,
RedirectStandardOutput = true,
};
// 子プロセスを起動する
using (var child = Process.Start(psi)) {
// リダイレクトされた子プロセスの標準入出力を取得する
var stdin = child.StandardInput;
var stdout = child.StandardOutput;
// BaseStreamを参照して標準入出力のStreamを取得し、
// BinaryWriter/BinaryReaderを作成する
using (var stdinWriter = new BinaryWriter(stdin.BaseStream)) {
// 6バイトのバイナリデータを標準入力へ書き込む
stdinWriter.Write(new byte[] {0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x21});
} // 子プロセスの標準入力を閉じて書き込みを終了する
byte[] output = null;
using (var stdoutReader = new BinaryReader(stdout.BaseStream)) {
// 標準出力から最大16バイトのバイナリデータを読み込む
output = stdoutReader.ReadBytes(16);
}
// 子プロセスの終了を待機する
child.WaitForExit();
// 読み込んだバイナリデータ文字列に変換して表示する
Console.WriteLine(Encoding.ASCII.GetString(output));
}
}
}
using System;
using System.IO;
using System.Security.Cryptography;
class Sample {
static void Main()
{
// 標準入力のStreamを取得
var input = Console.OpenStandardInput();
// 標準出力のStreamをベースに、書き込まれる内容を
// BASE64エンコードするCryptoStreamを作成する
using (var output = new CryptoStream(
Console.OpenStandardOutput(),
new ToBase64Transform(),
CryptoStreamMode.Write,
leaveOpen: true
)) {
// 入力ストリームの内容を出力ストリームに書き込む
// (BASE64エンコードされた上で書き込まれる)
input.CopyTo(output);
}
}
}
>parent.exe
SGVsbG8h
StandardInput/StandardOutput/StandardErrorで取得できるStreamWriter/StreamReaderは内部でバッファリングが行われます。 このため、StandardInput/StandardOutput/StandardErrorを使った読み書きと、BaseStreamから取得したStreamへの読み書きを混在させると入出力内容に不整合が起こる(入出力されるデータの一部の順序が前後する)可能性があり、両者の使用は排他的とする必要があります。
つまり、BaseStreamから取得したStreamで読み書きを行う場合は、それのみを使って読み書きを行う、あるいはどちらか一方をFlushするまではもう一方を使って読み書きしないようにします。
Windows上では、BaseStreamプロパティから取得したStreamを閉じたあとにStandardOutput/StandardErrorを閉じると、StreamWriterがFlushしようとして例外ObjectDisposedExceptionがスローされます。 そのため、StreamWriterとBaseStreamプロパティから取得したStreamの両方をCloseしないように(二重にCloseする動作とならないように)注意する必要があります。
自プロセスの標準ストリームのStreamを取得する方法については自プロセスの標準入出力 §.標準ストリームの取得を参照してください。
Streamクラスを使った読み書きの方法についてはストリームの基本とStreamクラス、BinaryWriterクラス/BinaryReaderクラスを使った読み書きの方法についてはBinaryReaderクラス・BinaryWriterクラスを参照してください。