2017-09-25 78 views
1

我试图按照Mkyong的说明通过Java代码调用shell命令。我的代码是:从Java代码调用shell命令时无法获得输出

public class ExecuteShellCommand { 

    public static void main(){ 
     String absolutePath = "/home/marievi/Downloads/small.mp4"; 
     String command = "ffmpeg -i " + absolutePath; 
     ExecuteShellCommand obj = new ExecuteShellCommand(); 
     String output = obj.executeCommand(command); 
     System.out.println(output); 
    } 

    public String executeCommand(String command) { 

     StringBuffer output = new StringBuffer(); 

     Process p; 
     try { 
      p = Runtime.getRuntime().exec(command); 
      p.waitFor(); 
      BufferedReader reader = 
        new BufferedReader(new InputStreamReader(p.getInputStream())); 

      String line = ""; 
      while ((line = reader.readLine()) != null) { 
       output.append(line + "\n"); 
      } 

     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     return output.toString(); 
    } 
} 

但我得到一个空的输出,只有一个换行符被打印。然而,当我运行Mkyong的例子的代码:

public static void main(){ 
    ExecuteShellCommand obj = new ExecuteShellCommand(); 
    String domainName = "google.com"; 
    String command = "ping -c 3 " + domainName; 
    String output = obj.executeCommand(command); 
    System.out.println(output); 
} 

输出被打印。任何想法出了什么问题?当我直接执行命令:命令行

ffmpeg -i /home/marievi/Downloads/small.mp4 

,我得到所需的输出:

ffmpeg version 3.3.4-1~14.04.york1 Copyright (c) 2000-2017 the FFmpeg developers 
    built with gcc 4.8 (Ubuntu 4.8.4-2ubuntu1~14.04.3) 
    configuration: --prefix=/usr --extra-version='1~14.04.york1' --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --enable-gpl --disable-stripping --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmp3lame --enable-libopenjpeg --enable-libmodplug --enable-libopus --enable-libpulse --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-omx --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libopencv --enable-libx264 --enable-shared 
    libavutil  55. 58.100/55. 58.100 
    libavcodec  57. 89.100/57. 89.100 
    libavformat 57. 71.100/57. 71.100 
    libavdevice 57. 6.100/57. 6.100 
    libavfilter  6. 82.100/6. 82.100 
    libavresample 3. 5. 0/3. 5. 0 
    libswscale  4. 6.100/4. 6.100 
    libswresample 2. 7.100/2. 7.100 
    libpostproc 54. 5.100/54. 5.100 
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/home/maxez/Downloads/small.mp4': 
    Metadata: 
    major_brand  : mp42 
    minor_version : 0 
    compatible_brands: mp42isomavc1 
    creation_time : 2010-03-20T21:29:11.000000Z 
    encoder   : HandBrake 0.9.4 2009112300 
    Duration: 00:00:05.57, start: 0.000000, bitrate: 551 kb/s 
    Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1/0x31637661), yuv420p(tv, bt709), 560x320, 465 kb/s, 30 fps, 30 tbr, 90k tbn, 60 tbc (default) 
    Metadata: 
     creation_time : 2010-03-20T21:29:11.000000Z 
     encoder   : JVT/AVC Coding 
    Stream #0:1(eng): Audio: aac (LC) (mp4a/0x6134706D), 48000 Hz, mono, fltp, 83 kb/s (default) 
    Metadata: 
     creation_time : 2010-03-20T21:29:11.000000Z 
+0

是否缺少在'absolutePath'斜线?因为“家/马里维/ ...”不是绝对路径。应该是'/ home/marievi/...'(查看变量'absolutePath'的声明)。 – Jesper

+0

@Jesper我不会错过'/',这是一个错字,编辑,对不起。 – Marievi

+0

我认为这是一个错字,但只是想确认,以确保它不是你的实际问题。在你的Java代码中,路径实际上与你给出的直接命令的路径不同。 IE使用'/ marievi'而不是'/ maxez'。 –

回答

2

帮你个忙,避免依赖mkyong.com。该网站只是在公共文件中反复出现一些可以轻松找到的内容,而不考虑其建议有多糟或过时,或者信息的陈旧程度如何。

事实上,Runtime.exec在最后的已经过时了十三年。在Java 5中推出的替代方案是ProcessBuilder。通过使用ProcessBuilder,您可以允许将外部进程的错误输出显示在Java程序错误输出的相同位置。目前,你没有在任何地方展示它,所以没有办法知道出了什么问题。

同样,StringBuffer已经过时并且非常旧;它的替代品是StringBuilder。它们是相同的,只是StringBuffer有额外的线程安全开销,这是很少用的。

此外,waitFor()等待过程结束。显然,那么在读取过程的输出之前,你不应该调用它。读完所有输出行后调用它。

最后,一个异常意味着“操作没有成功,你不应该继续,就好像它成功了。”如果你遇到异常,你的进程没有成功。由于读取过程的输出对于你想要做的事情来说很重要,所以继续下去是没有意义的。相反,将任何捕获的异常包装在未经检查的异常中,如RuntimeException。 (一个更好的选择将是彻底消除了try/catch语句,以及将这些异常类型的throws条款您executeCommand和主要方法。)

public static void main() { 
    String absolutePath = "/home/marievi/Downloads/small.mp4"; 
    String[] command = { "ffmpeg", "-i", absolutePath }; 
    ExecuteShellCommand obj = new ExecuteShellCommand(); 
    String output = obj.executeCommand(command); 
    System.out.println(output); 
} 

public String executeCommand(String[] command) { 

    StringBuilder output = new StringBuilder(); 

    try { 
     ProcessBuilder builder = new ProcessBuilder(command); 
     // Share standard input/output/error descriptors with Java process... 
     builder.inheritIO(); 
     // ... except standard output, so we can read it with getInputStream(). 
     builder.redirectOutput(ProcessBuilder.Redirect.PIPE); 

     Process p = builder.start(); 

     try (BufferedReader reader = 
      new BufferedReader(new InputStreamReader(p.getInputStream()))) { 

      String line = ""; 
      while ((line = reader.readLine()) != null) { 
       output.append(line + "\n"); 
      } 
     } 

     p.waitFor(); 

    } catch (IOException | InterruptedException e) { 
     // Process failed; do not attempt to continue! 
     throw new RuntimeException(e); 
    } 

    return output.toString(); 
} 
+0

尽管提问者没有提及所有这些细节 - 这确实是一个更有用的答案。 – ospf

1

没有什么不对您的代码。 只有ffmpeg写入stderr而不是stdout。

您可以通过将getInputStream()替换为getErrorStream()来使其工作。

+0

非常感谢! – Marievi