Spring Boot项目执行Sox命令失败(退出码1)问题排查
问题
我的项目包含音频块,正在实现REST API以在音频块发生变更时更新项目。需要将音频块合并并在块间添加间隔,之后将合并后的音频上传回S3存储(音频文件存储于S3中)。我在EC2上运行的Spring Boot项目中执行已安装的Sox命令,但调用函数时返回退出码1,音频块未完成带间隔的合并。在普通Java文件中执行相同Runtime命令可正常运行,但部署后的Spring Boot项目中无法正常工作,相关代码如下:
public void mergeBlocks(Long teamId, Long projectId){ try { List<Block> blocks = blockRepository.findByProjectId(projectId); long length = 0; AudioInputStream clip = null; List<AudioInputStream> list = new ArrayList<AudioInputStream>(); new File(String.valueOf(projectId)).mkdirs(); for (Block b: blocks) { FileOutputStream fos = new FileOutputStream(new File(projectId + "/temp" + b.getId() + ".wav")); S3Object o = amazonS3Client.getObject(AUDIO_BUCKET_NAME, teamId + "/" + projectId + "/" + b.getId() + ".wav"); S3ObjectInputStream s3is = o.getObjectContent(); byte[] read_buf = new byte[1024]; int read_len = 0; while ((read_len = s3is.read(read_buf)) > 0) { fos.write(read_buf, 0, read_len); } fos.close(); String[] cmd = {"sox", projectId + "\\temp" + b.getId() + ".wav", projectId + "\\interval" + b.getId() + ".wav", "pad", "0", String.valueOf(b.getInterval())}; try { Runtime rt = Runtime.getRuntime(); Process pr = rt.exec(cmd); BufferedReader input = new BufferedReader(new InputStreamReader(pr.getInputStream())); String line = null; while ((line = input.readLine()) != null) { System.out.println(line); } int exitVal = pr.waitFor(); System.out.println("Exited with error code " + exitVal); } catch(Exception e) { System.out.println(e.toString()); e.printStackTrace(); } clip = AudioSystem.getAudioInputStream(new File(projectId + "/interval" + b.getId() + ".wav")); list.add(clip); length += clip.getFrameLength(); } if(length>0 && list.size()>0 && clip!=null) { AudioInputStream appendedFiles = new AudioInputStream( new SequenceInputStream(Collections.enumeration(list)), clip.getFormat(), length); AudioSystem.write(appendedFiles, AudioFileFormat.Type.WAVE, new File(projectId + "/appended.wav")); } clip.close(); amazonS3Client.putObject(AUDIO_BUCKET_NAME, teamId + "/" + projectId + "/0.wav", new File(projectId + "/appended.wav")); FileUtils.deleteDirectory(new File(String.valueOf(projectId))); } catch (AmazonServiceException e) { System.err.println(e.getErrorMessage()); System.exit(1); } catch (FileNotFoundException e) { System.err.println(e.getMessage()); System.exit(1); } catch (IOException e) { System.err.println(e.getMessage()); System.exit(1); } catch (UnsupportedAudioFileException e) { e.printStackTrace(); } }
我尝试使用Java Runtime.getRuntime().exec(cmd)执行Sox命令,期望在Spring Boot项目中能成功执行该命令,请问是否是目录路径的问题?
回答
- 路径分隔符不匹配:你在代码里混合使用了两种路径分隔符——创建临时文件用的是
/,但Sox命令里用的是\\。EC2通常运行Linux系统,路径分隔符是/,\\是Windows的分隔符,这会导致Sox找不到输入文件,直接返回错误码1。把Sox命令里的\\全部改成/即可解决这个核心问题。 - 工作目录差异:普通Java程序和Spring Boot部署后的工作目录不同。普通Java程序的工作目录是你运行命令的目录,而Spring Boot以jar包运行时,工作目录可能是jar所在目录或Tomcat临时目录。建议使用绝对路径创建临时目录和文件(比如
/tmp/下的子目录),避免依赖当前工作目录。 - 未捕获Sox错误输出:你只读取了Sox的标准输出,但错误信息会输出到标准错误流。添加以下代码读取错误流,能看到Sox具体的错误提示,更易定位问题:
BufferedReader errorReader = new BufferedReader(new InputStreamReader(pr.getErrorStream())); String errorLine; while ((errorLine = errorReader.readLine()) != null) { System.err.println("Sox错误输出:" + errorLine); } - 权限问题:Spring Boot运行的用户(如tomcat用户、ec2-user)可能没有临时目录的读写权限,或没有执行Sox命令的权限。检查临时目录权限,确保运行用户有读写权限;同时确认Sox命令的路径在该用户的环境变量PATH中,或直接使用Sox的绝对路径(比如
/usr/bin/sox)执行命令。
内容的提问来源于stack exchange,提问作者tlfdksro
相关产品推荐
相关产品推荐

