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

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

Я использую 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+"\\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>";

Как подключить 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.

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


person Hrishikesh Choudhari    schedule 28.06.2012    source источник
comment
Не следует ли переместить pb.start в конец программы? (после bw.write(content); Просто догадка, основанная на том, как мы пишем в процесс после его запуска!   -  person Sap    schedule 02.08.2012
comment
@Grrrrr ну, я думаю, нам нужно запустить процесс, чтобы получить его выходной поток.   -  person Hrishikesh Choudhari    schedule 02.08.2012
comment
Вы записываете данные в выходной поток, это означает, что вы записываете данные в процесс! Если вы хотите получить результат процесса, вам следует выполнить process.getInputStream, а затем прочитать его.   -  person Sap    schedule 02.08.2012
comment
Вы читаете поток ошибок? Возможно, подпроцесс выдает ошибку и завершается. Если вы не читаете поток ошибок, вы никогда не узнаете.   -  person Christopher Schultz    schedule 07.08.2012
comment
Я нахожу getOutputStream очень неясным именем для фактической цели: Возвращает выходной поток, подключенный к обычному входу подпроцесса. Вывод в поток направляется на стандартный ввод процесса, представленного этим объектом Process. В python он просто называется stdin, но тогда можно утверждать, что запись в нечто с именем stdin семантически некорректна.   -  person Aurélien Ooms    schedule 02.09.2014


Ответы (5)


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

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

person Volker Stolz    schedule 10.08.2012

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

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

person Peter Lawrey    schedule 07.08.2012
comment
Поток ошибок процесса сказал то же самое - Труба закончилась. - person Hrishikesh Choudhari; 09.08.2012
comment
Я никогда не видел программы, которая выдает такую ​​ошибку при запуске из командной строки. - person Peter Lawrey; 09.08.2012
comment
Я нашел этот вывод из ошибки: java.io.BufferedReader@2512b853 - person Hrishikesh Choudhari; 09.08.2012
comment
Это означает, что вы печатаете объект BufferedReader вместо того, чтобы читать его с помощью readLine() и распечатывать его. - person Peter Lawrey; 09.08.2012

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

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

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

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

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

Вместо этого я бы рекомендовал использовать BufferedReader и записывать его непосредственно в поток вывода, прежде чем добавлять дополнительную строку. Затем вызовите 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();
}
person Rajesh J Advani    schedule 06.08.2012

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

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

person Andrzej Doyle    schedule 28.06.2012
comment
Я использую getOutputStream и пишу в процесс из буфера. Я делаю это правильно? Я обновил вопрос. - person Hrishikesh Choudhari; 28.06.2012

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

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;
    }
}
person Xolve    schedule 10.08.2012