0

我在 java Web 服务中有以下代码:

public boolean makeFile(String fileName, String audio)
    {
        if (makeUserFolder())
        {
            File file = new File(getUserFolderPath() + fileName + amr);
            FileOutputStream fileOutputStream = null;
            try
            {

                file.createNewFile();
                fileOutputStream = new FileOutputStream(file);
                fileOutputStream.write(Base64.decode(audio));

                return true;

            }
            catch(FileNotFoundException ex)
            {
                return false;
            }
            catch(IOException ex)
            {
                return false;
            }
            finally{
                try {
                    fileOutputStream.close();
                    convertFile(fileName);
                } catch (IOException ex) {
                    Logger.getLogger(FileUtils.class.getName()).log(Level.SEVERE, null, ex);
            }
}

        }
        else
            return false;

    }

    public boolean convertFile(String fileName)
    {
        Process ffmpeg;
        String filePath = this.userFolderPath + fileName;
        try {
            ProcessBuilder pb = new ProcessBuilder("ffmpeg","-i",filePath + amr,filePath + mp3);
            pb.redirectErrorStream();
            ffmpeg = pb.start();
        } catch (IOException ex) {
            return false;
        }
        return true;
    }

它曾经可以工作,现在由于某种原因它根本不会执行 ffmpeg 转换。我认为这是我的文件的问题,但是在从终端运行命令后没有抛出任何错误或任何东西,认为这可能是权限问题,但所有权限都已在我保存文件的文件夹中授予。我注意到在运行进程后输入的 BufferedReader ins 被设置为 null,知道发生了什么吗?

4

1 回答 1

5

首先,对您的代码进行一个小挑剔......当您创建时,FileOutputStream您使用字符串而不是 a 创建它File,当您已经创建了File之前,所以您不妨回收它而不是强制FileOutputStream实例化File自身.

另一个小问题是,当您写出音频文件时,您应该将其包含在一个try块中并在一个块中关闭输出流finally。如果你被允许在你的项目中添加一个新的库,你可能会使用Guava,它有一个方法Files.write(byte[],File),它将为你处理所有脏资源管理。

我能看到的唯一看起来像一个明确错误的事实是您忽略了 ffmpeg 的错误流。如果您阻止等待 ffmpeg 的标准输出上的输入,那么它将不起作用。

处理此错误的最简单方法是使用ProcessBuilder而不是Runtime.

ProcessBuilder pb = new ProcessBuilder("ffmpeg","-i",filePath+amr,filePath+mp3);
pb.redirectErrorStream(); // This will make both stdout and stderr be redirected to process.getInputStream();
ffmpeg = pb.start();

如果您以这种方式启动它,那么您当前的代码将能够完全读取两个输入流。stderr 可能隐藏了一些您由于未阅读而无法看到的错误。

如果那不是您的问题,我建议您使用 ffmpeg 的绝对路径...换句话说:

String lastdot = file.getName().lastIndexOf('.');
File mp3file = new File(file.getParentFile(),file.getName().substring(0,lastdot)+".mp3");
ProcessBuilder pb = new ProcessBuilder("ffmpeg","-i",file.getAbsolutePath(),mp3file.getAbsolutePath());
// ...

如果这不起作用,我也会将 ffmpeg 更改为绝对路径(以排除路径问题)。

编辑:进一步的建议。

我会亲自将编写代码重构为自己的方法,以便您可以在其他必要的地方使用它。换句话说:

public static boolean write(byte[] content, File to) {
    FileOutputStream fos = new FileOutputStream(to);
    try {
        fos.write(content);
    } catch (IOException io) {
        // logging code here
        return false;
    } finally {
        closeQuietly(fos);
    }
    return true;
}
public static void closeQuietly(Closeable toClose) {
    if ( toClose == null ) { return; }
    try {
        toClose.close();
    } catch (IOException e) {
        // logging code here
    } 
}

我之所以做这个closeQuietly(Closeable)方法,是因为如果你不这样关闭它,有可能该close()方法会抛出异常,而那个异常会掩盖原本抛出的异常。如果您将它们放在实用程序类中(尽管查看您的代码,我假设它当前所在的类名为 FileUtils),那么您将能够在需要处理文件输出时在整个应用程序中使用它们。

这将允许您将块重写为:

File file = new File(getUserFolderPath() + fileName + amr);
file.createNewFile()
write(Base64.decode(audio),file);
convertFile(fileName);

我不知道你是否应该这样做,但是如果你想确保 ffmpeg 进程已经完成,那么你应该说ffmpeg.waitFor();确保它已经完成。如果你这样做,那么你应该检查ffmpeg.exitValue();以确保它成功完成。

您可能想做的另一件事是,一旦完成,将输出的内容写入日志文件,这样您就可以记录发生的事情,以防万一发生。

于 2011-02-17T23:46:52.853 回答