Я пытаюсь изменить свою библиотеку классов, которая взаимодействует с клиентом командной строки Mercurial, и в клиенте 1.9 появилась новая возможность вращать сервер и общаться с ним по стандартным каналам ввода-вывода. Это действительно многообещающе, поскольку одна из основных проблем использования клиента командной строки Mercurial заключается в том, что, поскольку он написан на Python, у него возникают некоторые проблемы, даже если он запрашивает его версию.
Однако есть одна проблема. До сих пор я получал выходные данные из клиента командной строки, читая стандартный вывод / ошибку, и когда процесс завершается, потоки сбрасываются, и я могу прочитать конец потока.
Однако в этом новом режиме процесс выгрузит много текста в стандартную ошибку / вывод, а затем будет сидеть в ожидании следующей команды. Отлично подходит для сокращения накладных расходов, но паршиво, поскольку .NET буферизует эти потоки.
Другими словами, поскольку процесс не завершается, я не получаю последнюю часть этого вывода, пока:
- Я прошу процесс выйти
- Я ввожу другую команду
Есть ли способ для меня
- Попросить буфер очистить, что означает, что я получаю все, что находится в буфере, даже если этого недостаточно, чтобы буфер очищался сам?
- Если нет, могу ли я установить размер буфера в 1 символ?
- Что-нибудь еще, что я могу сделать?
Я могу справиться с P / Invoke, если это то, что нужно.
Вот LINQPad программа для проверки концепции, которая будет иллюстрировать:
То, что он делает, это раскручивает командную строку и передает ей команду DIR, однако обратите внимание, что только после того, как эти 10 секунд пройдут внутри цикла, программа выведет приглашение «C:>», которое командная строка выдает сразу после создание списка каталогов.
Другими словами, это то, что делает командная строка:
- Создание списка каталогов
- Запросите другую команду, предложив "C:> \"
Однако вот что видит программа ниже:
- Составить список каталогов
- (подождите 10 секунд)
- Закрыть входной поток
См. Подсказку
void Main ()
{
string clientExecutablePath = "cmd.exe";
var psi = new ProcessStartInfo();
psi.FileName = clientExecutablePath;
psi.RedirectStandardError = true;
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.CreateNoWindow = true;
psi.WorkingDirectory = @"C:\";
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.UseShellExecute = false;
psi.ErrorDialog = false;
psi.StandardErrorEncoding = Encoding.GetEncoding("Windows-1252");
psi.StandardOutputEncoding = Encoding.GetEncoding("Windows-1252");
var p = Process.Start(psi);
var input = p.StandardInput;
var output = p.StandardOutput;
var error = p.StandardError;
Action<StreamReader, string> reader = delegate(StreamReader streamReader, string prefix)
{
string line;
while ((line = streamReader.ReadLine()) != null)
{
Debug.WriteLine(prefix + line);
}
};
IAsyncResult outputReader = reader.BeginInvoke(output, "o: ", null, null);
IAsyncResult errorReader = reader.BeginInvoke(error, "e: ", null, null);
input.Write("dir\n");
input.Flush();
while (!p.HasExited)
{
Thread.Sleep(10000);
input.Close();
}
reader.EndInvoke(outputReader);
reader.EndInvoke(errorReader);
}