Java中Process和Runtime()使用,以及调用cmd命令阻塞解决

Java使用Process执行一段cmd命令,2.5M文件运行没问题,稍大的文件就不能写入。如果关闭进程则进行写入。经调查是cmd命令阻塞原因。

java调用cmd执行bat文件有时会出现卡死的现象,当时感觉很迷惑,后来查资料,本来一般都是这样来调用程序并获取进程的输出流的,但是我在windows上执行这样的调用的时候却总是在while那里被堵塞了,结果造成ffmpeg程序在执行了一会后不再执行,这里从官方的参考文档中我们可以看到这是由于缓冲区的问题,由于java进程没有清空ffmpeg程序写到缓冲区的内容,结果导致ffmpeg程序一直在等待。在网上也查找了很多这样的问题,不过说的都是使用单独的线程来进行控制,我也尝试过很多网是所说的方法,可一直没起什么作用。一直认为是getInputStream的缓冲区没有被清空,不过问题确实是缓冲区的内容没有被清空,但不是getInputStream的,而是getErrorStream的缓冲区,这样问题就得到解决了。所以我们在遇到java调用外部程序而导致线程阻塞的时候,可以考虑使用两个线程来同时清空process获取的两个输入流,如下这段程序:

public String excuteBatFile(String file, boolean isCloseWindow) 
    {
        String cmdCommand = null;
        String res = null;
        if(isCloseWindow) 
        {
            cmdCommand = "cmd.exe /c " + file;
        }else 
        {
            cmdCommand = "cmd.exe /k " + file;
        }
        StringBuilder stringBuilder = new StringBuilder();
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(cmdCommand);
            final InputStream is1 = process.getInputStream();
            new Thread(new Runnable() {
                public void run() {
                    BufferedReader bufferedReader = null;
                    String line = null;
                    try {
                        bufferedReader = new BufferedReader(
                                new InputStreamReader(is1, "GBK"));
                        while((line=bufferedReader.readLine()) != null) 
                        {
                            stringBuilder.append(line+"\n");
                        }
                        is1.close();
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }).start(); // 启动单独的线程来清空p.getInputStream()的缓冲区
            InputStream is2 = process.getErrorStream();
            BufferedReader br2 = new BufferedReader(new InputStreamReader(is2)); 
            StringBuilder buf = new StringBuilder(); // 保存输出结果流
            String line2 = null;
            while((line2 = br2.readLine()) != null) buf.append(line2); // 
            log.info("----res:----" + stringBuilder + "&" + buf);
            return stringBuilder + "&" + buf;
        } catch (Exception e) {
            e.printStackTrace();
            return e.toString();
        }
    }

通过这样我们使用一个线程来读取process.getInputStream()的输出流,使用另外一个线程来获取process.getErrorStream()的输出流,这样我们就可以保证缓冲区得到及时的清空而不担心线程被阻塞了。当然根据需要你也可以保留process.getInputStream()流中的内容,这个就看调用的程序的处理了。

上我的代码

cmd方法调用

//执行cmd命令,写入mesh块
		String[] cmdLine = new String[] {toolpath,"\"" + lodpath + "\"","\"" + meshpath + "\"","\"" + splitpath + "\"","\"" + maxsize + "\"","\"" + lodlevel + "\""};
		boolean flag = useCmd(cmdLine);

cmd使用及阻塞解决

public boolean useCmd(String[] cmdLine){
		StringBuilder stringBuilder = new StringBuilder();
		Process process = null;
		int retval = -1;
		int exitval= -1;
		try {
			//process = Runtime.getRuntime().exec( "C:\\tool\\split\\lodmeshsplit\\LodMeshSplit.exe \"E:\\SViewCloud2.0\\data\\splited\\5aea563a38674af7ae1d8820a0666435\\御景佳园2C#3D.prt.lod\" \"E:\\SViewCloud2.0\\data\\splited\\5aea563a38674af7ae1d8820a0666435\\御景佳园2C#3D.prt.mesh\" \"E:\\SViewCloud2.0\\data\\splited\\5aea563a38674af7ae1d8820a0666435\\071441d9631c4592afe2a18a45ed65cf\" \"71000\" \"0\"");
			process = Runtime.getRuntime().exec(cmdLine);
			final InputStream is1 = process.getInputStream();
			new Thread(new Runnable() {
				public void run() {
					BufferedReader bufferedReader = null;
					String line = null;
					try {
						bufferedReader = new BufferedReader(new InputStreamReader(is1, "GBK"));
						while ((line = bufferedReader.readLine()) != null) {
							stringBuilder.append(line + "\n");
						}
						is1.close();
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}).start(); // 启动单独的线程来清空p.getInputStream()的缓冲区;
			InputStream is2 = process.getErrorStream();
			BufferedReader br2 = new BufferedReader(new InputStreamReader(is2));
			StringBuilder buf = new StringBuilder(); // 保存输出结果流
			String line2 = null;
			while((line2 = br2.readLine()) != null) buf.append(line2); //
			System.out.println("----res:----" + stringBuilder + "&" + buf);
			//return stringBuilder + "&" + buf;
			retval = process.waitFor();
			exitval = process.exitValue();

		} catch (IOException | InterruptedException e) {
			e.printStackTrace();
		}
		if (retval == 0 && exitval == 0) {
			return true;
		}else{
			return false;
		}
	}


————————————————
原文链接:https://blog.csdn.net/hantanxin/article/details/103957871/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值