2012-06-28 20 views
8

Passare al secondo aggiornamento. Non volevo cambiare il contesto precedente di questa domanda.Come inviare InputStream a ProcessBuilder

Sto usando wkhtmltoimage da un'app Java.

Il modo standard di utilizzo è - path-to-exe http://url.com/ image.png.

Secondo i loro documenti, se scriviamo un - anziché un URL di input, l'input si sposta su STDIN.

sto iniziando il processo utilizzando ProcessBuilder -

ProcessBuilder pb = new ProcessBuilder(exe_path, " - ", image_save_path); 

Process process = pb.start(); 

Ora sono in grado di capire come tubo di un flusso di input a questo processo.

Ho un file di modello di leggere in un DataInputStream, e sto aggiungendo una stringa alla fine:

DataInputStream dis = new DataInputStream (new FileInputStream (currentDirectory+"\\bin\\template.txt")); 
byte[] datainBytes = new byte[dis.available()]; 
dis.readFully(datainBytes); 
dis.close(); 

String content = new String(datainBytes, 0, datainBytes.length); 

content+=" <body><div id='chartContainer'><small>Loading chart...</small></div></body></html>"; 

Come faccio a tubo content al STDIN del processo?

UPDATE ---

In seguito alla risposta da Andrzej Doyle:

Ho usato il getOutputStream() del processo:

ProcessBuilder pb = new ProcessBuilder(full_path, " - ", image_save_path); 

    pb.redirectErrorStream(true); 

    Process process = pb.start();   

    System.out.println("reading"); 

    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(process.getOutputStream())); 

    bw.write(content); 

In questo modo dà un errore che dice:

Exception in thread "main" java.io.IOException: The pipe has been ended 

2 ° AGGIORNAMENTO --------

Il blocco di codice corrente è in quanto tale:

try { 
     ProcessBuilder pb = new ProcessBuilder(full_path, "--crop-w", width, "--crop-h", height, " - ", image_save_path); 
     System.out.print(full_path+ "--crop-w"+ width+ "--crop-h"+ height+" "+ currentDirectory+"temp.html "+ image_save_path + " "); 
     pb.redirectErrorStream(true); 

     Process process = pb.start(); 
     process.waitFor(); 
     OutputStream stdin = process.getOutputStream(); 

     BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin)); 
// content is the string that I want to write to the process. 

     writer.write(content); 
     writer.newLine(); 
     writer.flush(); 
     writer.close(); 


    } catch (Exception e) { 
     System.out.println("Exception: " + e); 
     e.printStackTrace(); 
    } 

L'esecuzione del codice di cui sopra mi dà un IOException: The pipe is being closed.

Cos'altro devo fare tenere la pipa aperta?

+0

non si dovrebbe muovere pb.start alla fine del programma? (dopo bw.write (contenuto); Solo un sospetto basato su "come scrivere su un processo dopo che è stato avviato!" – Sap

+0

@Grrrrr beh, penso che avremmo bisogno di avviare un processo per ottenere il suo outputstream. –

+3

Stai scrivendo i dati nell'output che si traduce in "stai scrivendo dati nel processo!" Se vuoi ottenere l'output del processo, dovresti fare process.getInputStream e poi leggerlo – Sap

risposta

3

Rimuovere gli spazi dal " - " - la normale gli spazi bianchi vengono rimossi dal parser della shell, ma qui nello ProcessBuilder, viene interpretato come il nome file (letterale) che inizia e termina con uno spazio bianco.

(In realtà guardando l'output del processo come Peter suggerito probabilmente ti hanno detto così ...)

3

Dopo aver creato l'oggetto Process, è possibile chiamare getOutputStream() per ottenere uno stream che invia il suo contenuto all'input standard del processo.

Una volta in possesso di questo, è possibile utilizzare l'IO standard di Java per scrivere qualsiasi byte sul flusso desiderato (incluso il wrapping in un writer, aggiungendo il buffering, ecc.) E mentre li si scrive, verranno essere letti dal processo non appena vengono scaricati.

+0

Sto usando 'getOutputStream' e sto scrivendo sul processo da un buffer. Lo sto facendo correttamente? Ho aggiornato la domanda. –

5

C'è un motivo per cui si sta utilizzando DataInputStream per leggere un semplice file di testo? Dalla documentazione Java

A data input stream lets an application read primitive Java data types from an underlying input stream in a machine-independent way

E 'possibile che il modo in cui si sta leggendo il file provoca un EOF da inviare al OutputStream causando il tubo per terminare prima che arrivi alla stringa.

I requisiti sembrano essere di leggere il file semplicemente per aggiungerlo prima di passarlo al processo wkhtmltoimage.

Inoltre manca un'istruzione per chiudere l'outputstream al processo. Ciò causerà l'attesa (hang) del processo fino a quando non otterrà un EOF dal flusso di input, che non sarebbe mai.

Si consiglia di utilizzare invece BufferedReader e di scriverlo direttamente nell'output prima di aggiungere la stringa aggiuntiva. Quindi chiama close() per chiudere il flusso.

ProcessBuilder pb = new ProcessBuilder(full_path, " - ", image_save_path); 
pb.redirectErrorStream(true); 

Process process = null; 
try { 
    process = pb.start(); 
} catch (IOException e) { 
    System.out.println("Couldn't start the process."); 
    e.printStackTrace(); 
} 

System.out.println("reading"); 

try { 
    if (process != null) { 
     BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(process.getOutputStream())); 

     BufferedReader inputFile = new BufferedReader(new InputStreamReader(new FileInputStream(currentDirectory+"\\bin\\template.txt"))); 

     String currInputLine = null; 
     while((currInputLine = inputFile.readLine()) != null) { 
      bw.write(currInputLine); 
      bw.newLine(); 
     } 
     bw.write("<body><div id='chartContainer'><small>Loading chart...</small></div></body></html>"); 
     bw.newLine(); 
     bw.close(); 
    } 
} catch (IOException e) { 
    System.out.println("Either couldn't read from the template file or couldn't write to the OutputStream."); 
    e.printStackTrace(); 
} 

BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream())); 

String currLine = null; 
try { 
    while((currLine = br.readLine()) != null) { 
     System.out.println(currLine); 
    } 
} catch (IOException e) { 
    System.out.println("Couldn't read the output."); 
    e.printStackTrace(); 
} 
+0

Questa soluzione ha funzionato per il mio caso, grazie per averlo pubblicato !!! –

6

Exception in thread "main" java.io.IOException: The pipe has been ended

Questo significa che il processo si è avviato è morto. Ti suggerisco di leggere l'output per capire perché. per esempio. ti ha dato un errore

+0

Il flusso di errori del processo ha detto la stessa cosa: "La pipa è terminata". –

+0

Ho anche aggiunto un comando 'waitFor':' process.waitFor(); ' –

+0

Non ho mai visto un programma che dia un tale errore quando viene eseguito dalla riga di comando. –

1

Il seguente codice funziona così:

import java.io.*; 
import java.util.*; 

public class ProcessTest { 

    public static void main(String[] args) throws Exception { 
     ProcessBuilder pb = new ProcessBuilder("/home/me/stdinecho"); 
     pb.redirectOutput(ProcessBuilder.Redirect.INHERIT); 
     Process proc = pb.start(); 

     // Input file 
     DataInputStream din = new DataInputStream((new FileInputStream("/home/me/stdinecho.cp"))); 
     byte[] dinBytes = new byte[din.available()]; 
     din.readFully(dinBytes); 
     din.close(); 
     String content = new String(dinBytes, 0, dinBytes.length); 
     content = "header\n" + content + "\nfooter"; 

     BufferedInputStream procStdout = new BufferedInputStream(proc.getInputStream()); 
     OutputStream stdin = proc.getOutputStream(); 

     stdin.write(content.getBytes()); 
     stdin.flush(); 
    } 

} 

Ecco stdinecho.cpp è il programma che emette la linea è entrato nel suo messaggio:

#include <iostream> 
#include <fstream> 
#include <cstdio> 

using namespace std; 

int main() 
{ 
    string strOutput; 
    string str; 
    while(getline(cin, str)) { 
     cout << str << endl; 
    } 
}