[gelöst] TProcess die Output Textdatei abfangen PDF in Text

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Namos

[gelöst] TProcess die Output Textdatei abfangen PDF in Text

Beitrag von Namos »

Ist es möglich die Textdatei, die ein Programm, das über TProcess aufgerufen wird, direkt abzufangen und in einen MemoryStream oder was anderes zu speichern.
Das Aufrufen klappt schon mal und die Parameterübergabe. Das aufgerufene Programm ist ein Kommandozeilenprogramm, das eine PDF Datei aufnimmt und in eine Textdatei umwandelt. Kann ich diesen Output direkt abfangen und wenn möglich das speichern auf der Festplatte verhindern ?

Mit dem Code aus dem Tutorial klappt es jedenfallt nicht (Einlesen eines großen Outputs (auf wiki.freepascal)), die Ausgabe bleibt lehr. Keine Fehlermeldung. Oder wird hier nur die Ausgabe von Programmmeldungen abgefagt ?

Code: Alles auswählen

procedure TForm1.Button2Click(Sender: TObject);
//   Copyright (c) 2004 by Marc Weustink
const
  READ_BYTES = 2048;
var
  S: TStringList;
  M: TMemoryStream;
  P: TProcess;
  n: LongInt;
  BytesRead: LongInt;
begin
   M := TMemoryStream.Create;
   BytesRead := 0;
 
   P := TProcess.Create(nil);
   P.Executable := 'pdfintxt.exe';
   P.Parameters.Add('Datei.pdf');
   P.Options := [poUsePipes, poNoConsole];
   Memo1.Lines.Add('-- executing --');
   P.Execute;
   while P.Running do
   begin
     // stellt sicher, dass wir Platz haben
     M.SetSize(BytesRead + READ_BYTES);
 
     // versuche, es zu lesen
     n := P.Output.Read((M.Memory + BytesRead)^, READ_BYTES);
     if n > 0
     then begin
       Inc(BytesRead, n);
       Write('.')
     end
     else begin
       // keine Daten, warte 100 ms
       Sleep(100);
     end;
   end;
   // lese den letzten Teil
   repeat
     // stellt sicher, dass wir Platz haben
     M.SetSize(BytesRead + READ_BYTES);
     // versuche es zu lesen
     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);
   Memo1.Lines.Add('-- executed --');
 
   S := TStringList.Create;
   S.LoadFromStream(M);
   Memo1.Lines.Add('-- linecount = ' + IntToStr(S.Count)+' --');
   for n := 0 to S.Count - 1 do
   begin
     Memo1.Lines.Add('| '+ S[n]);
   end;
   Memo1.Lines.Add('-- end --');
   S.Free;
   P.Free;
   M.Free;
 end;
Zuletzt geändert von Namos am Do 9. Mai 2013, 11:09, insgesamt 6-mal geändert.

wp_xyz
Beiträge: 5167
Registriert: Fr 8. Apr 2011, 09:01

Re: TProcess die Output Textdatei abfangen

Beitrag von wp_xyz »

Mir hat in einem ähnlichen Fall der ShellCommandRunner von http://www.lazarus.freepascal.org/index ... 15.15.html geholfen.

Namos

Re: TProcess die Output Textdatei abfangen

Beitrag von Namos »

Danke für die Anwort. Ich habe es gerade ausprobiert. Es läuft ohne Fehler, aber der Output bleibt leer.
Das Programm (pdftotxt aus XPDF http://www.foolabs.com/xpdf/download.html) erzeugt in dem Kommandozeilenfenster keinen Output, sondern erzeugt wie gesagt nur ein Textfile.
Kann man das überhaupt abfangen ?
Hier noch der Code den ich verwendet habe:

Code: Alles auswählen

uses ...ShellCommandRunner ...
 
  ...
type
  TfrmMain1 = class(TForm)
  ...
  private
    procedure OnOutputAvailable(const pBuffer: PByteArray; const pCount: integer);
  ...
 
implementation
 
procedure TForm1.Button1Click(Sender: TObject);  // Test button to start the threaded dir command
var
  th: TShellCommandRunnerThread;
begin
  th := TShellCommandRunnerThread.Create;
  th.CommandLine:= 'pdfintext.exe Datei.pdf';
  th.OnOutputAvailable := @OnOutputAvailable;
  th.Start;
end;
 
// Capture the output
procedure TForm1.OnOutputAvailable(const pBuffer: PByteArray;
  const pCount: integer);
begin
  Memo1.Append(TShellCommandRunner.BufferToString(pBuffer,pCount));
end;
shellcommandrunner.zip
TShellCommandRunner von eny aus diesem Beitrag: http://www.lazarus.freepascal.org/index.php/topic,17315.15.html
(14.76 KiB) 94-mal heruntergeladen
Zuletzt geändert von Namos am Do 9. Mai 2013, 11:08, insgesamt 3-mal geändert.

wp_xyz
Beiträge: 5167
Registriert: Fr 8. Apr 2011, 09:01

Re: TProcess die Output Textdatei abfangen

Beitrag von wp_xyz »

Verwende mal einen Bindestrich als Dateinamen, damit sollte der Output in die Standardausgabe gehen (http://linux.die.net/man/1/pdftotext)

Namos

Re: TProcess die Output Textdatei abfangen

Beitrag von Namos »

Vielen Dank das geht einwandfrei ! :D

Code: Alles auswählen

th.CommandLine:= 'pdfintext.exe Datei.pdf -';
Zuletzt geändert von Namos am Do 9. Mai 2013, 11:09, insgesamt 1-mal geändert.

Namos

Re: [Gelöst] TProcess die Output Textdatei abfangen PDF in T

Beitrag von Namos »

So ich habe mal das Beispiel aus dem Wiki http://wiki.freepascal.org/Executing_Ex ... en_Outputs etwas geändert. Das geht jetzt auch und man braucht die shellcommandrunner.pas nicht dafür. Allerdings kommt mir das ganze etwas langsamer vor (habe es aber nicht getestet mit einem Timer). Außerdem braucht es ca. 1,2 MB mehr Speicher bei mir (getestet mit 1MB PDF). Warum weiß ich leider nicht. Vielleicht wird irgendwas nicht sauber freigegeben.

Code: Alles auswählen

procedure TForm1.Button2Click(Sender: TObject);
const
  READ_BYTES = 4096;
var
  MemStrm: TMemoryStream;
  Proc: TProcess;
  n: LongInt;
  BytesRead: LongInt;
begin
   BytesRead := 0;
   MemStrm := TMemoryStream.Create;
   Proc := TProcess.Create(nil);
 
   try
     Proc.Executable := 'pdfintext.exe'; //auszuführendes Programm
     Proc.Parameters.Add('Datei.pdf');
     Proc.Parameters.Add('-'); // - heißt das der Output in der Konsole erfolgt und so abgefragt werden kann
     Proc.Options := [poUsePipes, poStderrToOutPut];
     Proc.ShowWindow := swoHide; //Fenster der Konsole nicht anzeigen
     Proc.Execute;
 
     while Proc.Running do
     begin
       // stellt sicher, dass wir Platz haben
       MemStrm.SetSize(BytesRead + READ_BYTES);
 
       // versuche, es zu lesen
       n := Proc.Output.Read((MemStrm.Memory + BytesRead)^, READ_BYTES);
       if n > 0
       then begin
         Inc(BytesRead, n);
       end
       else begin
         // keine Daten, warte 50 ms
         Sleep(50);
       end;
     end;
     // lese den letzten Teil
     repeat
       // stellt sicher, dass wir Platz haben
       MemStrm.SetSize(BytesRead + READ_BYTES);
       // versuche es zu lesen
       n := Proc.Output.Read((MemStrm.Memory + BytesRead)^, READ_BYTES);
       if n > 0 then begin
         Inc(BytesRead, n);
       end;
     until n <= 0;
     MemStrm.SetSize(BytesRead);
 
     //Ausgabe
     Memo1.Lines.LoadFromStream(MemStrm);
   finally
     //Speicherfreigabe
     FreeAndNil(Proc);
     FreeAndNil(MemStrm);
   end;
 end;
MfG

Antworten