java.lang.Runtime.exec的左膀右臂:流输入和流读取详解

Java提供了Runtime.exec()方法来启动一个新进程。该方法可以返回Process对象,通过该对象可以控制和管理子进程的输入、输出以及错误流。这个方法中的参数是一个字符串,它描述了一个shell命令,应该如何来运行这个新的子进程。

为了更好地使用exec()方法,在使用exec()的时候,我们应该学会:

1.正确处理进程输出

2.合并输出流,正确地处理错误

3.增加进程的交互

4.通常的编程技巧

下面我们将详细讲解一下这个问题。

一. 确定进程输出

一旦启动一个进程,子进程处理输出流,而主进程负责处理输入和错误。通常情况下,这意味着你应该在一个线程中完成一个任务,而其他的线程则负责读取和处理输出,确保没有线程会阻塞等待运行子进程的输出。

输出有时被缓冲,因此要求读取器定期刷新来将缓冲区中的数据充满。下面的代码展示了一个如何启动UNIX进程的例子:

import java.io.*;
public class Test {
  public static void main(String[] args) throws IOException {
    Runtime rt = Runtime.getRuntime();
    Process proc = rt.exec("ls");
    InputStream stdin = proc.getInputStream();
    InputStreamReader isr = new InputStreamReader(stdin);
    BufferedReader br = new BufferedReader(isr);
    String line = null;
    System.out.println("<OUTPUT>");
    while ( (line = br.readLine()) != null)
      System.out.println(line);
    System.out.println("</OUTPUT>");
    int exitVal = proc.waitFor();
    System.out.println("Process exitValue: " + exitVal);
  }
}

注意到我们启动子进程的时候并没有提供输出程序到主进程的管道。相反,子进程的输出流(在这种情况下是ls的输出)被start()方法连接到新的InputStreamReader,并连接可以传递到缓冲的BufferedReader。然后,我们部分读取由子进程生成的结果并将其显示在主进程的STDOUT上。

二. 合并输出流,正确处理错误

Java允许三种不同的标准进程流:

1.输入流:包括子进程对标准输入流(System.in)的使用。

2.输出流:包括子进程对标准输出流(System.out)和标准错误流(System.err)的使用。

3.错误流:该流用于报告错误,这些错误对于诊断问题很有用。

大多数情况下,我们应该为每种类型的流创建单独的进程来处理特定的工作。但也有时候,显式地为子进程指定流已经足够。这种方法特别适合于与系统进程通信的应用程序(例如,爬虫程序或者系统监视器)。

下面的代码演示了如何合并输出流,并分离错误流。

import java.io.*;
public class Test {
  public static void main(String[] args) throws IOException {
    Runtime rt = Runtime.getRuntime();
    String[] cmd = {"ls", "-al"};
    Process proc = rt.exec(cmd);
    InputStream stdin = proc.getInputStream();
    InputStreamReader isr = new InputStreamReader(stdin);
    BufferedReader br = new BufferedReader(isr);
    InputStream stderr = proc.getErrorStream();
    InputStreamReader esr = new InputStreamReader(stderr);
    BufferedReader ebr = new BufferedReader(esr);
    String line = null;
    System.out.println("<OUTPUT>");
    while ( (line = br.readLine()) != null)
      System.out.println(line);
    System.out.println("</OUTPUT>");
    System.out.println("<ERROR>");
    while ( (line = ebr.readLine()) != null)
      System.out.println(line);
    System.out.println("</ERROR>");
    int exitVal = proc.waitFor();
    System.out.println("Process exitValue: " + exitVal);
  }
}

三. 增加进程的交互

下列示例演示了如何启动一个交互式进程,并发送输入到用不同于按下Enter键的方式回答问题。下面的程序会启动iconv,该程序是一个Unix将不同字符编码转换成一种标准字符编码的命令行实用程序。

import java.io.*;
public class Test {
  public static void main(String[] args) throws IOException {
    Runtime rt = Runtime.getRuntime();
    Process proc = rt.exec("iconv -f ISO-8859-1 -t UTF-8");
    OutputStream out = proc.getOutputStream();
    InputStream in = proc.getInputStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
    PrintWriter writer = new PrintWriter(out);
    String[] messages = {"food", "coat", "car"};
    for (String message : messages) {
      writer.println(message);
      String line = reader.readLine();
      System.out.println(line);
    }
    writer.println("quit");
    writer.flush();
    int exitVal = proc.waitFor();
    System.out.println("Process exitValue: " + exitVal);
  }
}

四. 通常的编程技巧

当使用ProcessBuilder,Runtime.exec()或System()等方法启动另一个的JVM时,也可以被称为Java调用时,我们需要使用Process.waitFor()等方法等待子进程完成。这里给出完整的示例:

import java.io.*;
public class Test {
  public static void main(String[] args) throws IOException, InterruptedException {
    String command = "java -cp ./example.jar com.mycompany.app.Main";
    ProcessBuilder builder = new ProcessBuilder(command.split("\\s+"));
    builder.directory(new File("/home/user/"));
    builder.redirectOutput(new File("/home/user/output.txt"));
    Process process = builder.start();
    int exitValue = process.waitFor();
    if (exitValue == 0) {
      System.out.println("Process exited without errors");
    } else {
      System.out.println("Process exited with errors");
    }
  }
}

在这个示例中,我们使用ProcessBuilder来启动一个Java应用程序,该程序包含在example.jar中,并且该应用程序的Main类位于com.mycompany.app包中。操作目录被设置为/home/user路径。标准输出被重定向到一个名为output.txt的文件。最后在waitFor()方法中等待进程结束,如果进程完全正确执行将返回0,否则返回非0。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java.lang.Runtime.exec的左膀右臂:流输入和流读取详解 - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • struts2中实现多个文件同时上传代码

    当在Struts2中需要同时上传多个文件时,需要进行以下几个步骤: 1.在JSP中设置表单属性 enctype=multipart/form-data,以便能够上传文件。 <form action="upload.action" method="post" enctype="multipart/form…

    Java 2023年5月20日
    00
  • Java实现数据库连接池的方法

    Java实现数据库连接池是一种提高性能和应用程序响应能力的有效方法。下面为大家介绍几种常见的Java实现数据库连接池的方法。 使用Apache DBCP实现连接池 Apache DBCP是Java中最常用的开源连接池之一,它是一个开源项目,由Apache软件基金会支持。它使用轻量级语言Java实现,可以通过简单的配置使用。下面是使用Apache DBCP实现…

    Java 2023年5月19日
    00
  • 解读Spring事务是如何实现的

    下面是关于解读Spring事务实现的攻略。 什么是Spring事务? Spring事务是一种管理数据库事务的机制。Spring提供了一种将事务管理到服务层的方式,从而统一处理事务。它提供了在事务中进行数据操作的方法,当操作失败时,能够自动将已经对数据库做出的更改撤销。 Spring如何管理事务? Spring管理事务的核心是通过AOP,即面向切面编程,将调用…

    Java 2023年5月20日
    00
  • spring security自定义登录页面

    下面是 Spring Security 自定义登录页面的完整攻略。 一、Spring Security 自定义登录页面的原理 Spring Security 默认提供了一个登录页面,但是我们可以通过自定义登录页面来满足自己的需求。实现自定义登录页面的方法主要包括以下几步: 创建一个登录页面; 在 Spring Security 配置文件中设置自定义登录页面的…

    Java 2023年5月20日
    00
  • spring 和 spring boot 中的属性配置方式

    Spring和Spring Boot中的属性配置方式 Spring和Spring Boot都提供了多种属性配置方式,本文将详细介绍这些方式,并提供两个示例。 Spring中的属性配置方式 Spring中的属性配置方式有以下几种: 1. 使用XML配置文件 使用XML配置文件是Spring最早的属性配置方式。在XML配置文件中,我们可以使用元素来定义Bean,…

    Java 2023年5月15日
    00
  • Java 异步实现的几种方式小结

    Java 异步实现的几种方式小结 在Java编程中,异步操作是一个非常重要的概念。我们通常都会遇到需要异步处理的场景,比如调用远程资源、IO阻塞等。异步操作的最大优势就在于能让程序运行更高效,提升整个系统的吞吐量。本文将对Java中实现异步的几种方式进行详细讲解。 方式一:使用Java 8及以后版本的CompletableFuture Completable…

    Java 2023年5月18日
    00
  • 怎么开启Java小程序脚本? 浏览器采用Java小程序脚本的技巧

    开启Java小程序脚本: Java小程序(Java applet)是用Java语言编写的小程序,可以在网络浏览器上运行,为在浏览器中使用Java小程序,需要遵循以下步骤: 安装Java运行环境(Java runtime environment,JRE),只要在Java官网下载JRE安装即可,注意选择与你电脑系统相匹配的版本。 将Java小程序嵌入到HTML页…

    Java 2023年5月23日
    00
  • SpringMVC接收复杂集合对象(参数)代码示例

    SpringMVC接收复杂集合对象(参数)代码示例 在SpringMVC中,我们可以使用@RequestParam注解来接收复杂集合对象(参数)。下面是一个示例代码,演示如何接收复杂集合对象(参数)。 示例代码 @RestController @RequestMapping("/api") public class MyControlle…

    Java 2023年5月18日
    00
合作推广
合作推广
分享本页
返回顶部