Executing External Programs/sk
│
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.