Как передать InputStream в ProcessBuilder

пожалуйста, перейдите ко 2-му обновлению. Я не хотел менять предыдущий контекст этого вопроса.

я использую wkhtmltoimage из приложения Java.

стандартный способ его использования - path-to-exe http://url.com/ image.png.

согласно их документам, если мы напишем - вместо входного URL-адреса ввод смещается на STDIN.

Я начинаю процесс с помощью ProcessBuilder -

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

Process process = pb.start();

теперь я не могу понять, как передайте входной поток в этот процесс.

у меня есть файл шаблона читайте в DataInputStream, и я добавляю строку в конце:

DataInputStream dis = new DataInputStream (new FileInputStream (currentDirectory+"bintemplate.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>";

как я трубы content до STDIN процесса?

обновление---

после ответа Анджея Дойла:

я использовал getOutputStream() процесс:

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);

это дает ошибку, говоря:

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

2-й Обновление--------

текущий блок кода таков:

    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();
    }

запуск вышеуказанного кода дает мне IOException: The pipe is being closed.

что еще мне нужно сделать, чтобы держать трубу открытой?

5 ответов


удалите пробелы из " - " -- обычные пробелы удаляются синтаксическим анализатором оболочки, но здесь, в ProcessBuilder, он интерпретируется как (буквальное) имя файла, начинающееся и заканчивающееся пробелом.

(На самом деле, глядя на результат процесса, как предложил Питер, вероятно, сказал бы вам об этом...)


исключение в потоке" main " java.Ио.IOException: труба была завершена

это означает, что процесс, который вы начали, умер. Я предлагаю вам прочитать результат, чтобы понять, почему. например, это дало вам ошибку.


есть ли причина, по которой вы используете DataInputStream для чтения простого текстового файла? Из документации Java

поток ввода данных позволяет приложению читать примитивные типы данных Java из базового входного потока машинно-независимым способом

возможно, что способ, которым Вы читаете файл, вызывает отправку EOF в outputstream, в результате чего канал заканчивается, прежде чем он попадет в вашу строку.

вам кажется, что требования чтобы прочитать файл, просто добавьте к нему, прежде чем передавать его в процесс wkhtmltoimage.

вам также не хватает оператора, чтобы закрыть outputstream для процесса. Это заставит процесс ждать (зависать), пока он не получит EOF из входного потока, который никогда не будет.

Я бы рекомендовал использовать BufferedReader вместо этого и записать его непосредственно в outputstream перед добавлением дополнительной строки. Затем вызовите close (), чтобы закрыть поток.

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();
}

после создания Process объект, вы можете вызвать getOutputStream() чтобы получить поток, который отправляет его содержимое на стандартный ввод процесса.

Как только вы овладеете этим, вы можете использовать стандартный IO Java для записи любых байтов в этот поток, который вы хотите (включая обертывание его в Writer, добавление буферизации и т. д.)- и как только вы их напишете, они будут прочитаны процессом, как только они будут смыты.


следующий код также работает:

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();
    }

}

здесь stdinecho.cpp-это программа, которая выводит строку, введенную в ее приглашение:

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

using namespace std;

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