Взаимодействие Octave и Lazarus/FreePascal с TProcess

Я также задавал этот вопрос на форумах Lazarus, здесь

Я пытаюсь связаться с Octave через TProcess, но, похоже, я не могу прочитать из него какие-либо байты. Прилагается блок основной формы; полное демо-приложение доступно в виде zip-архива на форуме под моим сообщением.

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, Process;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;
  POctave: TProcess;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
begin
  if (not POctave.Running) then
  begin
    POctave.Executable := 'C:\Octave\Octave-4.2.0\bin\octave-cli.exe';
    POctave.Parameters.Add('--no-gui');
    POctave.Options := [poUsePipes];
    WriteLn('-- Executing octave --');
    POctave.Execute;
  end;

end;

procedure TForm1.Button2Click(Sender: TObject);
var
  command: string;
  Buffer: string;
  BytesAvailable: DWord;
  BytesRead: longint;
  NoMoreOutput: boolean;
begin
  command := 'pwd' + #10;
  if (POctave.Running) then
    POctave.Input.Write(command, Length(command));

  if (POctave.Running) then
  begin
    BytesAvailable := POctave.Output.NumBytesAvailable;
    BytesRead := 0;
    while BytesAvailable > 0 do
    begin
      SetLength(Buffer, BytesAvailable);
      BytesRead := POctave.OutPut.Read(Buffer[1], BytesAvailable);
      WriteLn(Buffer);
      BytesAvailable := POctave.Output.NumBytesAvailable;
      NoMoreOutput := False;
    end;
  end;
end;

initialization
  POctave := TProcess.Create(nil);

finalization
  POctave.Free;

end.

Я добавил подпрограммы сна и изменил значение возврата команды pwd на #1310, оба безуспешно.

    procedure TForm1.Button2Click(Sender: TObject);
var
  command: ansistring;
  Buffer: string;
  BytesAvailable: DWord;
  BytesRead: longint;
  NoMoreOutput: boolean;
begin
  command := 'pwd'#13#10;
  if (POctave.Running) then
    POctave.Input.Write(command, Length(command));
  Sleep(100);

  if (POctave.Running) then
begin
    Sleep(100);
    BytesAvailable := POctave.Output.NumBytesAvailable;
    BytesRead := 0;
    while BytesAvailable > 0 do
    begin
      Sleep(100);
      SetLength(Buffer, BytesAvailable);
      BytesRead := POctave.OutPut.Read(Buffer[1], BytesAvailable);
      WriteLn(Buffer);
      BytesAvailable := POctave.Output.NumBytesAvailable;
      NoMoreOutput := False;
    end;
  end;
end;   

person trayres    schedule 13.02.2017    source источник
comment
вы немедленно прерываете работу, когда нет доступных байтов, а октава не самая быстрая из программ.   -  person Marco van de Voort    schedule 14.02.2017
comment
К сожалению, я пытался добавить сон в подпрограммы, чтобы учесть задержку, но безуспешно.   -  person trayres    schedule 14.02.2017
comment
Можете ли вы запустить «octave --eval 1+1»? POctave.Parameters.Add('--eval');POctave.Parameters.Add('1+1'); И кстати: что вы действительно хотите заархивировать? Controle Octave через трубы?   -  person Andy    schedule 14.02.2017


Ответы (1)


Проблема была в том, что я вызывал эту строку:

POctave.Input.Write(command, Length(command));

вместо этого:

POctave.Input.Write(command[1], Length(command));

После изменения этого (И ДОБАВЛЕНИЯ ЗАДЕРЖКИ! Ждать результата было абсолютно критично, но моя ошибка была более фундаментальной.)

Помните: строки Pascal не являются строками C. Упс...

Это сработало! Теперь я могу отправлять команды в Octave и получать результаты через конвейеры. :)

person trayres    schedule 14.02.2017
comment
Не используйте Sleep(...). Вместо этого добавьте poWaitOnExit в параметры TProcess (см. wiki.freepascal.org/Executing_External_Programs#TProcess). ) - person wp_1233996; 16.02.2017
comment
На самом деле я собираюсь выгрузить из Octave несколько довольно больших матриц; если я использую poWaitOnExit и буфер заполняется, это может привести к взаимоблокировке. - person trayres; 16.02.2017