Executing External Programs/sk
From Lazarus-ccr
Deutsch (de) English (en) Español (es) Français (fr) Japanese (ja) Nederlands (nl) Português (pt) Русский (ru) Slovensky (sk)
Contents |
[edit] Úvod
Je mnoho spôsobov ako spustiť externé programy. Zameriame sa na jeden z nich.
[edit] 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']);
[edit] 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ú...
[edit] 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.
[edit] 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.
[edit] Čí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.
[edit] Použitie vstupu a výstupu z TProcess
Viz príklad processdemo na Lazarus-CCR SVN.
[edit] 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 {...}
[edit] 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.
