七叶笔记 » java编程 » java调用shell脚本及注意事项说明

java调用shell脚本及注意事项说明

需求

get方法下载远程zip包,然后zip包解压,取出第一级目录再次进行压缩获取新的压缩zip包。

问题

如果选择使用java代码的IO流操作,在不确定zip包大小的情况下可能会占用很大的内存,所以选择异步调用shell脚本来实现这个操作;

介绍

1、通过ProcessBuilder进行调度

2、直接通过系统的Runtime类执行shell

Runtime类封装了运行时的环境。每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。

一般不能实例化一个Runtime对象,应用程序也不能创建自己的 Runtime 类实例,但可以通过 getRuntime 方法获取当前Runtime运行时对象的引用。

一旦得到了一个当前的Runtime对象的引用,就可以调用Runtime对象的方法去控制Java虚拟机的状态和行为。 

遇到的问题

1、没权限运行

通过ProcessBuilder来设置文件的权限

2、调用shell脚本提示:No such file or directory

原因:文件格式不正确导致,在windows下编写的sh文件,文件是DOS格式。使用:set ff=unix 强制将文件转换为unix格式。

具体操作:

vim模式打开这个shell脚本,查看编码格式后设置成unix编码,输入:set ff?,查看格式是否是fileformat=unix;如果不是,设置成unix

:set ff=unix后保存(:wq)即可。

3、shell脚本输出太大,程序卡死问题

Java在执行Runtime.getRuntime().exec(command)之后,Linux会创建一个进程,该进程与JVM进程建立三个管道连接,标准输入流、标准输出流、标准错误流。

当标准输出流或标准错误流非常庞大的时候,会出现调用waitFor方法卡死的bug。真实的环境中,当标准输出在10000行左右的时候,就会出现卡死的情况。

原因分析:

假设linux进程不断向标准输出流和标准错误流写数据,而JVM却不读取,数据会暂存在linux缓存区,当缓存区存满之后导致该进程无法继续写数据,会僵死,导致java进程会卡死在waitFor()处,永远无法结束。

解决方式:

由于标准输出和错误输出都会向Linux缓存区写数据,而脚本如何输出这两种流是Java端不能确定的。为了不让shell脚本的子进程卡死,这两种输出需要分别读取,而且不能互相影响。所以必须新开两个线程来进行读取。

下面提供工具类和自己的shell脚本

工具类

shell脚本

以上为个人经验,希望能给大家一个参考,也希望大家多多支持七叶笔记。 

相关文章