Вывод JAVA исполняемого файла (выполняемого с помощью ProcessBuilder) не перенаправляется на консоль

Я делаю консольное приложение Java для Windows, которое читает буфер обмена пользователя, и если контент является ссылкой https://youtube.com , загружает аудио в файл mp3 с помощью youtube-dl.

Я пытался использовать ProcessBuilder для загрузки и преобразования видео в аудио, но мне не удается перенаправить вывод youtube-dl.exe на консоль.

package com.awidesky.YoutubeClipboardAutoDownlader;

import java.io.File;
import java.io.FilenameFilter;
import java.lang.ProcessBuilder.Redirect;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

public class YoutubeAudioDownloader {

    private static final String youtubedlpath = new File("").getAbsolutePath() + "\\resources\\ffmpeg\\bin"; //Thread.currentThread().getContextClassLoader().getResource("ffmpeg/bin").getPath();
    private static File downloadPath;
    
    static {
        
        if (!new File(youtubedlpath + "\\youtube-dl.exe").exists()) { throw new Error("youtube-dl.exe does not exist!"); }

    }
    
    static void download(String url, String path) throws Exception {
        
        downloadPath = new File(path);
        
        try {
            
            //Main.log(downloadPath.getAbsolutePath());
            ProcessBuilder pb = new ProcessBuilder(youtubedlpath + "\\youtube-dl", "-x", "--audio-format", "mp3", "--audio-quality", "0",  url);
            pb.directory(new File(youtubedlpath));
            Process p = pb.start();
            pb.redirectError(Redirect.INHERIT);
            pb.redirectOutput(Redirect.INHERIT);

            /*
             * Thread stdout = new Thread(() -> {
             * 
             * BufferedReader br = new BufferedReader(new
             * InputStreamReader(p.getInputStream())); String line = null;
             * 
             * try {
             * 
             * while((line = br.readLine ()) != null) {
             * 
             * Main.log(line);
             * 
             * }
             * 
             * } catch (IOException e) {
             * 
             * // TODO Auto-generated catch block Main.log(e.toString());
             * 
             * }
             * 
             * });
             * 
             * Thread stderr = new Thread(() -> {
             * 
             * BufferedReader br = new BufferedReader(new
             * InputStreamReader(p.getErrorStream())); String line = null;
             * 
             * try {
             * 
             * while((line = br.readLine ()) != null) {
             * 
             * Main.log(line);
             * 
             * }
             * 
             * } catch (IOException e) {
             * 
             * // TODO Auto-generated catch block Main.log(e.toString());
             * 
             * }
             * 
             * });
             * 
             * stdout.start(); stderr.start();
             */
             
            p.waitFor();
            
            
            //Thread.currentThread().sleep(100);
            
            Main.log("founding downloaded file...");
            
            File[] fileList = new File(youtubedlpath).listFiles(new FilenameFilter() {
                
                @Override
                public boolean accept(File dir, String name) {
                    // TODO Auto-generated method stub
                    return name.endsWith("mp3");
                }
                
            });
            
            if(fileList.length ==0 ) { throw new RuntimeException("Didn't dowload any files!"); }
            
            for(File f : fileList) {
                
                Files.copy(f.toPath(), Paths.get(downloadPath.getAbsolutePath() + "\\" + f.getName()) ,StandardCopyOption.REPLACE_EXISTING);
                Files.delete(f.toPath());
                
            }
            
            Main.log("Done!");
            
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        
    }
    
}

Если я получу InputStreamReader из Process p и использую два Thread и while для печати, я могу получить правильный вывод из eclipse, но я не могу получить его при запуске с java -jar YoutubeClipBoardAutoDownlaoder.jar.

И когда я использую pb.redirectError(Redirect.INHERIT); и pb.redirectOutput(Redirect.INHERIT);, ни консоль eclipse, ни консоль Windows я не получаю вывода. Где я ошибся?

  • Полные коды проекта находятся здесь а ниже это основной класс его.
package com.awidesky.YoutubeClipboardAutoDownlader;

import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.FlavorEvent;
import java.awt.datatransfer.FlavorListener;
import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.swing.JFileChooser;
import javax.swing.JFrame;

/** Main class */
public class Main {

    private static ExecutorService executorService = Executors.newFixedThreadPool(1);
    private static boolean isOkToStart = false; /** I don't know why but when you copied something, <code>flavorsChanged</code> invoked twice and we should ignore the first one. */
    
    public static void main(String[] args) throws Exception {

        JFileChooser jfc = new JFileChooser();
        jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        jfc.setDialogTitle("Choose directory for saving music!");
        jfc.showDialog(new JFrame(), null);
        File dir = jfc.getSelectedFile();
        
        Toolkit.getDefaultToolkit().getSystemClipboard().addFlavorListener(new FlavorListener() { 
        
                @Override 
                public void flavorsChanged(FlavorEvent e) {

                    if (!isOkToStart) { isOkToStart = true; return; } 

                    System.err.println("CLIPBOARD CHANGED");
                    
                    executorService.submit(() -> {
                        
                        try {
                        
                            Thread.sleep(100);
                            
                            String data = (String)Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.stringFlavor);
                    
                            if (data.startsWith("https://www.youtu")) {
                      
                                log("Receved a link from your clipboard : " + data);
                                YoutubeAudioDownloader.download(data, dir.getAbsolutePath());

                            }
                        
                        } catch(Exception err) {
                        
                            log(err.toString());
                        
                        }
               
                    });
                    
                    isOkToStart = !isOkToStart;
                    
                }
        
        });
        
        log("Listning clipboard...");
        
    }
    
    
    public static void log(String data) {
        
        System.out.println(data);
        
    }

}

Вы можете спросить меня...

  1. Вы ДОЛЖНЫ использовать youtuve-dl?

    -Неа. Единственная причина, по которой я использую это, заключается в том, что я не нашел лучшего для загрузки аудио с youtube.com.

  2. Почему вы используете только один пул потоков?

    - Избегайте длительного времени в потоке событий, и я думаю, что процессы падают, когда я запускаю несколько youtuve-dl.exe (хотя не уверен)


person eugene    schedule 17.07.2020    source источник


Ответы (2)


Вы должны перенаправить вывод до запуска процесса.

        pb.redirectError(Redirect.INHERIT);
        pb.redirectOutput(Redirect.INHERIT);
        Process p = pb.start();
person Donggi Kim    schedule 17.07.2020
comment
Выводы печатаются правильно в eclipse, но не тогда, когда я начал экспортировать файл jar ... Я думаю, что youtube-dl.exe вообще не выполнялся. Но это сработало отлично, когда я запустил его из eclipse! - person eugene; 17.07.2020
comment
Может быть, мне следует опубликовать еще один вопрос об экспорте проекта eclipse с двоичными файлами в файл .jar ...? - person eugene; 17.07.2020
comment
Это странно... Видите ли вы другие тексты System.out.println на консоли при запуске java -jar xxx.jar? Если можно, добавьте к своему вопросу вывод консоли. - person Donggi Kim; 17.07.2020
comment
Я получил такой вывод консоли: Listening clipboard... (новая строка) CLIPBOARD CHANGED (new line) Получена ссылка из вашего буфера обмена: youtube.com/blablabla Поскольку я не могу получить больше выходных данных (включая те, что из youtube-dl и System.out (например, «Готово!»)), я полагаю, что youtube-dl.exe не выполнялся, когда я запустите «java -jar xxx.jar». - person eugene; 17.07.2020

Я искал несколько недель и, наконец, получил его. Проблема была не в вводе-выводе, а в упаковке. Поскольку я поместил .exefile (youtube-dlfile) в свой jar, Java не смог найти файл.
Я поместил папку ресурсов за пределы .jar, и все заработало.
Но все же я не могу найти почему jvm не дал мне '''Error''' или '''Exception''' об этом (может быть, проблема с вводом-выводом?)

person eugene    schedule 14.09.2020