Executing External Programs/sk

From Free Pascal wiki
Jump to navigationJump to search

Deutsch (de) English (en) español (es) français (fr) italiano (it) 日本語 (ja) Nederlands (nl) polski (pl) português (pt) русский (ru) slovenčina (sk) 中文(中国大陆) (zh_CN)

Úvod

Je mnoho spôsobov ako spustiť externé programy. Zameriame sa na jeden z nich.

SysUtils.ExecuteProcess

najjednoduchší spôsob, ak nepotrebujete rúry (pipes) alebo žiadne formu ovládania je jednoducho použiť

 SysUtils.ExecuteProcess('/full/path/to/binary',['arg1','arg2']);

TProcess

Môžete použiť TProcess na spustenie externých programov. Výhody tohoto spôsobu sú:

  • Nezávislý na platforme
  • Schopnosť čítať zo stdin a stdout.
Poznámka: TProcess nie je terminal/shell! Nemôžete priamo spustiť alebo presmerovať výstup pomocou operátorov ako "|", ">", "<", "&" atď. Možno získať rovnaký výsledok s TProcess pomocou Pascal, príklady nasledujú...

Jednoduchý príklad

 // Toto je ukážkový program ktorý vám ukáže ako
 // spustiť externý program.
 program launchprogram;
 
 // Tu si "použijeme" unity ktoré budeme potrebovať
 uses 
   Classes, SysUtils, Process;
 
 // Toto je definícia premennej APRocess
 // typu "TProcess"
 var 
   AProcess: TProcess;
 
 // Začiatok programu
 begin
   // Vytvoríme objekt TProcess
   // pridelíme ho do premennej AProcess
   AProcess := TProcess.Create(nil);
 
   // Povieme novému procesu aký príkaz má vykonať
   // Použime FPC prekladač
   AProcess.CommandLine := 'ppc386 -h';
 
   // Definujeme nastavenie pre spustenie.
   // Toto nastavenie zaručí že náš program
   // nebude pokračovať až kým sa proces neskončí
   AProcess.Options := AProcess.Options + [poWaitOnExit];
 
   // Teraz keď už proces vie čo má robiť
   // ho môžeme spustiť.
   AProcess.Execute;
 
   // Toto sa dosiahne až po skončení procesu.
   AProcess.Free;   
 end.

To je všetko! Práve ste sa naučili ako spustit externý program použitím TProcess.

To je všetko pekné, ale ako získam výstup spusteného programu? Tak sa na to pozrime, trochu rozšírime náš priklad.

Vylepšený príklad

 // Toto je ukážkový program ktorý vám ukáže ako
 // spustiť externý program.
 program launchprogram;
 
 // Tu si "použijeme" unity ktoré budeme potrebovať
 uses 
   Classes, SysUtils, Process;
 
 // Toto je definícia premennej APRocess
 // typu "TProcess"
 // Teraz pridáme aj TStringList aby sme
 // mohli uložiť výstup procesu.
 var 
   AProcess: TProcess;
   AStringList: TStringList;
 
 // Začiatok programu
 begin
   // Vytvoríme objekt TProcess
   // pridelíme ho do premennej AProcess
   AProcess := TProcess.Create(nil);
 
   // Vytvoríme TStringList a pridelíme ho
   AStringList := TStringList.Create;
 
   // Povieme novému procesu aký príkaz má vykonať
   // Použime FPC prekladač
   AProcess.CommandLine := 'ppc386 -h';
 
   // Definujeme nastavenie pre spustenie.
   // Toto nastavenie zaručí že náš program
   // nebude pokračovať až kým sa proces neskončí
   // Zároveň ho nastavíme tak, aby sme mohli
   // čítať výstup.
   AProcess.Options := AProcess.Options + [poWaitOnExit, poUsePipes];
 
   // Teraz keď už proces vie čo má robiť
   // ho môžeme spustiť.
   AProcess.Execute;
   
   // Toto sa dosiahne až po skončení procesu.
 
   // Teraz načítame výstup programu
   // do TStringListu.
   AStringList.LoadFromStream(AProcess.Output);
   
   // Uložíme výstup do súboru
   AStringList.SaveToFile('output.txt');
 
   // Teraz keď je už výstup uložený
   // môžeme uvolniť objekty.
   AStringList.Free;
   AProcess.Free;   
 end.

Čítanie veľkého výstupu

V predchádzajúcom príklade sme čakali na ukončenie programu a potom sme čítali čo mal program zapísané do výstupu. Ale predstavte si, že program zapisuje na výstup veľké množstvo dát, rúra sa plní a volaný program čaká na jej vyprázdnenie (prečítanie). Ale volajúci program z rúry nečíta, pretože čaká na ukončenie volaného programu. Nastalo uviaznutie.

Takže nasledujúci príklad nepoužíva poWaitOnExit, ale číta z výstupu, zatiaľ čo program stále beží. Výstup je uchovávaný v pamäťovom streame, ktorý môže byť neskôr použitý na prečítanie výstupu do TStringList.

 program procoutlarge;
 {
     Copyright (c) 2004 by Marc Weustink
 
     Tento príklad je vytvorený v nádeji, že bude užitočný,
     ale BEZ AKEJKOĽVEK ZÁRUKY; dokonca bez implicitnej záruky 
     MERCHANTABILITY alebo FITNESS FOR A PARTICULAR PURPOSE.
 }
 
 uses
   Classes, Process, SysUtils;
 
 const
   READ_BYTES = 2048;
   
 var
   S: TStringList;
   M: TMemoryStream;
   P: TProcess;
   n: LongInt;
   BytesRead: LongInt;
 
 begin
   // Nemôžeme tu použiť poWaitOnExit, lebo nepoznáme 
   // veľkosť výstupu. V Linuxe je veľkosť 
   // výstupnej rúry 2 kB. Ak je výstupných dátviac, 
   // musíme dáta prečítať. To však nie je možné, keďže 
   // sme čakajúci. Takže by tu nastalo uviaznutie.
   //
   // Na buferovanie výstupu použijeme dočasný Memorystream 
   
   M := TMemoryStream.Create;
   BytesRead := 0;
 
   P := TProcess.Create(nil);
   P.CommandLine := 'ppc386 -va bogus.pp';
   P.Options := [poUsePipes];
   WriteLn('-- executing --');
   P.Execute;
   while P.Running do
   begin          
     // overenie, že máme dosť priestoru
     M.SetSize(BytesRead + READ_BYTES);
     
     // skús ho prečítať
     n := P.Output.Read((M.Memory + BytesRead)^, READ_BYTES);
     if n > 0 
     then begin
       Inc(BytesRead, n);
       Write('.')
     end
     else begin     
       // žiadne dáta, počkať 100 ms
       Sleep(100); 
     end;
   end;
   // čítať poslednú časť
   repeat
     // overenie, že máme dosť priestoru
     M.SetSize(BytesRead + READ_BYTES);
     // skús ho prečítať
     n := P.Output.Read((M.Memory + BytesRead)^, READ_BYTES);
     if n > 0 
     then begin
       Inc(BytesRead, n);
       Write('.');
     end;
   until n <= 0;
   if BytesRead > 0 then WriteLn;
   M.SetSize(BytesRead); 
   WriteLn('-- executed --');
   
   S := TStringList.Create;
   S.LoadFromStream(M);
   WriteLn('-- linecount = ', S.Count, ' --');
   for n := 0 to S.Count - 1 do
   begin
     WriteLn('| ', S[n]);
   end;
   WriteLn('-- end --');
   S.Free;
   P.Free;
   M.Free;
 end.

Použitie vstupu a výstupu z TProcess

Viz príklad processdemo na Lazarus-CCR SVN.

Pokyny pre použitie TProcess

Ak vytvárate cez platformný program, môžete zmeniť príkazový riadok v závislosti na OS, pomocou direktív "{$IFDEF}s" a "{$ENDIF}s".

Príklad:

 {...}
   AProcess:TProcess.Create(nil)
   {$IFDEF WIN32}
   AProcess.CommandLine := 'calc.exe'; //Windows Calc
   {$ENDIF}
   {$IFDEF LINUX}
   AProcess.CommandLine := 'kcalc'; //KDE Calc
   {$ENDIF}
   AProcess.Execute; //in alternative, you can use AProcess.Active:=True
 {...}

Príklad komunikácie s procesom aspell

V zdrojovom kóde pasdoc môžete nájsť dve unity, ktoré vykonávajú kontrolu pravopisu komunikáciou s bežiacim procesom aspell cez rúry:

  • PasDoc_ProcessLineTalk.pas unit implementuje triedu TProcessLineTalk, potomka TProcess, ktorú možno jednoducho použiť na komunikáciu s ktorýmkoľvek procesom na báze riadok-po-riadku.
  • PasDoc_Aspell.pas unit implementuje triedu TAspellProcess, ktorá vykonáva kontrolu pravopisu pomocou základnej inštancie TProcessLineTalk pre spustenie aspell a komunikáciu so spusteným procesom aspell.

Obe jednotky sú vcelku nezávislé od zvyšku zdrojového kódu pasdoc, takže môžu poslúžiť ako príklady skutočného použitia TProcess na spustenie a komunikáciu s inými programmi cez rúry.