当字符串太长时,PrintWriter.print会阻塞

时间:2015-07-24 22:43:18

标签: java printwriter

我正在java中编写一个包装程序,它只是想通过在流中写入标准将参数传递给其他进程,并从标准输出流中读取响应。但是,当我尝试传入的String太大时,PrintWriter.print只会阻止。没有错误,只是冻结。这有一个很好的解决方法吗?

相关代码

public class Wrapper {
    PrintWriter writer;

    public Wrapper(String command){
        start(command);
    }

    public void call(String args){
        writer.println(args); // Blocks here
        writer.flush();

        //Other code
    }

    public void start(String command) {
        try {
            ProcessBuilder pb = new ProcessBuilder(command.split(" "));
            pb.redirectErrorStream(true);
            process = pb.start();
            // STDIN of the process.
            writer = new PrintWriter(new OutputStreamWriter(process.getOutputStream(), "UTF-8"));
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Process ended catastrophically.");
        }
    }


}

如果我尝试使用

writer.print(args);
writer.print("\n");

它可以在冻结之前处理更大的字符串,但最终还是会锁定。 是否可能有缓冲流方式来解决这个问题? print阻塞有足够空间的进程流吗?

更新

在回答一些答案和评论时,我提供了更多信息。

  • 操作系统是Windows 7
  • BufferedWriter减慢了运行时间,但最终没有阻止它。
  • 字符串可能会很长,最多可达100,000个字符
  • 过程输入被消耗,但是按行,即Scanner.nextLine();

测试代码

import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;

import ProcessRunner.Wrapper;


public class test {

    public static void main(String[] args){
        System.out.println("Building...");
        Wrapper w = new Wrapper("java echo");
        System.out.println("Calling...");
        String market = "aaaaaa";
        for(int i = 0; i < 1000; i++){
            try {
                System.out.println(w.call(market, 1000));
            } catch (InterruptedException | ExecutionException
                    | TimeoutException e) {

                System.out.println("Timed out");
            }
            market = market + market;
            System.out.println("Size = " + market.length());
        }
        System.out.println("Stopping...");
        try {
            w.stop();
        } catch (IOException e) {

            e.printStackTrace();
            System.out.println("Stop failed :(");
        }
    }
}

测试过程:

您必须首先编译此文件,并确保.class与测试.class文件位于同一文件夹中

import java.util.Scanner;


public class echo {

    public static void main(String[] args){
            while(true){
            Scanner stdIn = new Scanner(System.in);
            System.out.println(stdIn.nextLine());
            }
    }

}

2 个答案:

答案 0 :(得分:3)

我怀疑这里发生的事情是外部进程正在写入其标准输出。由于您的Java代码不读取它,它最终会填充外部进程的标准输出(或错误)管道。这会阻止外部进程,这意味着它可以从其输入管道中读取....并且您的Java进程会冻结。

如果这是问题,那么使用缓冲编写器将无法修复它。您需要读取外部进程输出或将其重定向到文件(例如Linux上的“/ dev / null”)

答案 1 :(得分:1)

如果对等点的读取速度比您正在写入的速度慢,则可以通过java.io块中的任何方式写入任何管道或套接字。

你无能为力。