【问题标题】:Command working on cmd but not in java code命令在 cmd 上工作,但不在 java 代码中
【发布时间】:2013-12-27 20:56:20
【问题描述】:

我正在使用 mkvmerge 将 avi 文件和 ass 文件合并为 mkv 文件。 我拥有可执行文件和 java 文件的当前目录位于名为 auto-mkvmerge 的文件夹中。 当我在命令行中使用以下命令时,它可以正常工作,mkvmerge.exe -o ../auto-done/098.mkv ../auto-vid/098.avi ../auto-sub/098.ass 我得到了正确的输出。 当我运行我的 java 代码时,它不起作用,并给我一个错误。

我的 java 代码。 主.java

import java.io.*;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        File vidDir = new File(args[0]);
        File subDir = new File(args[1]);
        File outDir = new File(args[2]);

        String[] vids = vidDir.list();
        String[] subs = subDir.list();

        for(int i = 0; i < vids.length; i++) {
            int r = mergeAviAndAss(vids[i], subs[i], args[2]);
        }
    }

    private static int mergeAviAndAss(String aviFileName, String assFileName, String doneDir) {
        try {
            ProcessBuilder pb = new ProcessBuilder("mkvmerge.exe", "-o", doneDir + "/" + aviFileName.substring(0, aviFileName.length() - 4) + ".mkv", "\"" + aviFileName + "\"", "\"" + assFileName + "\"");
            Process p = pb.start();

            InputStream inputStream = p.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));

            String line;
            while((line = br.readLine()) != null)
                System.out.println(line);

            return p.waitFor();
        } catch(IOException e) {
            e.printStackTrace();
        } catch(InterruptedException e) {
            e.printStackTrace();
        }

        return -1;
    }
}

当我使用以下行执行它时(编译我的 java 代码之后):java Main ../auto-vid ../auto-sub ../auto-done &gt; log.txt

mkvmerge v6.6.0 ('The Edge Of The In Between') built on Dec  1 2013 17:55:00

Error: The file '098.avi' could not be opened for reading: open file error.

mkvmerge v6.6.0 ('The Edge Of The In Between') built on Dec  1 2013 17:55:00

Error: The file '099.avi' could not be opened for reading: open file error.

mkvmerge v6.6.0 ('The Edge Of The In Between') built on Dec  1 2013 17:55:00

Error: The file '100.avi' could not be opened for reading: open file error.

mkvmerge v6.6.0 ('The Edge Of The In Between') built on Dec  1 2013 17:55:00

Error: The file '101.avi' could not be opened for reading: open file error.

mkvmerge v6.6.0 ('The Edge Of The In Between') built on Dec  1 2013 17:55:00

Error: The file '102.avi' could not be opened for reading: open file error.

mkvmerge v6.6.0 ('The Edge Of The In Between') built on Dec  1 2013 17:55:00

Error: The file '103.avi' could not be opened for reading: open file error.

我的代码是否有问题,或者我编写它的方式有问题,因为如果我在命令行中键入它时它可以正常工作,它应该可以在我的 java 代码中工作。

【问题讨论】:

  • 打开文件错误是否意味着文件无法打开,因为它没有找到,或者因为它当前有一些排他锁?可能很笨,但你确定你没有在另一个应用程序中打开文件吗?
  • 是的,我检查了,我什至打印了文件列表以检查它们的名称和扩展名是否正确,并且我确保它们没有打开。
  • 您可以尝试将构建的字符串写入您传递给流程构建器的 STDout,以验证该字符串没有任何问题吗?
  • 工作目录也可能对您的可执行文件很重要。尝试使用 pb.directory("PATH WITH THE FILES IN IT HERE"); 在您的流程构建器上设置工作目录在开始这个过程之前。
  • 我尝试将avi和ass文件与mkvmerge.exe和我的java文件放在同一目录下,它工作正常

标签: java command-line processbuilder


【解决方案1】:

这是一个路径问题。你可以:

  • 运行您的 java 程序,传递视频文件的绝对路径:java Main c:\pathtovideo1\video1.mvk c:\pathtovideo2.avi ...
  • 进入所有视频所在的路径,执行 java c:\pathtomain\Main video1.mvk video2.avi ...
  • 最后,您可以在 java 中指定更复杂的代码来处理路径(为视频附加固定路径等)

如果此选项有效,您可以发现还有一个有效的相对路径,可能是 java Main ../auto-done/098.mkv ../auto-done/098.avi ...

【讨论】:

  • 第一个选项有效,但我希望能够指定包含文件的目录而不是文件本身。我正在尝试你写的第三个选项
  • 似乎唯一可行的选项是将所有文件与 exe 文件和 java 类放在同一目录中,所以这是我现在选择的选项。
【解决方案2】:

这是 techurbana 指出的路径问题。

在启动进程之前,您需要通过调用进程构建器的 .directory(String) 方法来设置进程的工作目录。你需要给它应用程序的根目录。

您可以通过以下操作获取 JAVA 可执行文件的当前工作目录(可能是也可能不是您存储 mkvmerg.exe 的位置):

 File dir = new File("");
 dir.getAbsolutePath();

如果您的 mkvmerg.exe 实用程序在您的系统中有一个类路径条目(无论如何在 Windows 上),您应该能够从任何目录运行 mkvmerg.exe。

然后,如果您希望 mkvmerge 在某个子文件夹中处理文件,请说 FolderA,您可以这样做:

 File subDir = new File(dir, "FolderA");
 subDir.getAbsolutePath();

只需尝试在运行时打印出您用于控制台的所有路径,以验证文件和可执行文件的路径是否正确,并且调试应该很快。

请查看以下管理路径的示例。它只是用记事本打开当前目录中的文件,但几乎正是您想要做的。要运行它,请将一些路径作为参数传递给 main()。

编辑 - 我刚刚意识到我从未真正使用传递给应用程序的路径,而只是在 java 可执行文件的当前目录中查找第一个文件,但你明白了。

 import java.io.BufferedReader;
 import java.io.File;
 import java.io.InputStream;
 import java.io.InputStreamReader;

 public class MainTest {

public static void main(String[] args) {
    // passes in a directory

    if (args.length > 0) {
        doSomethingWithCMD(args[0]);
    }
}

public static void doSomethingWithCMD(String filesDir) {


    try {
        File currDir = new File("");
        // this is a bit weird, but listFiles didnt return anything without
        // this next line.
        currDir = new File(currDir.getAbsolutePath());
        System.out.println(currDir.getAbsolutePath());

        // build our command with a string builder
        StringBuilder sb = new StringBuilder();

        // get the list of files
        File[] files = currDir.listFiles();

        // if there are no files this will be null so check first
        if (!(files == null)) {
            for (File f : files) {
                if (f.isFile()) {
                    sb.append("notepad ");
                    sb.append("\"" + f.getAbsolutePath());
                    sb.append("\"");
                    break;
                }
            }
        }
                    // create our process builder
        // first with no working dir & absolute paths
        ProcessBuilder pb = new ProcessBuilder(sb.toString());
        Process p = pb.start();

        InputStream inputStream = p.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(
                inputStream));

        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
        // cleanup
        try {
            inputStream.close();
        }
        catch (Exception ignore) {

        }
        try {
            br.close();
        }
        catch (Exception ignore) {

        }

        sb = new StringBuilder();
        // now we rebuild our command using relative paths instead of
        // absolute ones
        if (!(files == null)) {
            for (File f : files) {
                if (f.isFile()) {
                    sb.append("notepad ");
                    sb.append("\"" + f.getName());
                    sb.append("\"");
                    break;
                }
            }
        }

        pb = new ProcessBuilder(sb.toString());
                    //set the working directory
        pb.directory(currDir);
        p = pb.start();

        inputStream = p.getInputStream();
        br = new BufferedReader(new InputStreamReader(inputStream));

        line = null;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }

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

【讨论】:

  • 我尝试了将文件放在子文件夹中使用的方法,现在在获取文件数组的长度时出现 NullPointerException。
  • 我像你一样添加了dir对象,在运行java类的时候,我写了java Main auto-vid/ auto-sub/ auto-done/
【解决方案3】:

我认为您可以在 Windows 上使用Runtime.exec(java.lang.String[])Runtime.getRuntime().exec("cmd \c here goes your command") 来使用指定命令启动其控制台。

编辑:要运行所需的命令,请使用Runtime.getRuntime().exec("here goes your command")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-27
    • 1970-01-01
    • 2020-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-06
    相关资源
    最近更新 更多