2017-09-25 106 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