Tomcat公网服务器Runtime.exec报错:文件存在仍提示找不到目录
我之前在部署WebP转换功能到Linux服务器的Tomcat时,也碰到过完全一样的问题!明明本地跑的好好的,到线上就报“no such file or directory”,而且文件检测还显示存在。结合你的情况,这里有几个核心排查方向,亲测有效:
1. 别把整个命令当字符串传给exec()
这是最常见的坑!Runtime.getRuntime().exec(String)在Linux下不会自动用shell解析命令,如果你写的是exec("cwebp ./input.jpg -o ./output.webp"),系统会把整个字符串当成一个可执行文件的名字去找,自然找不到。
正确做法是把命令拆成字符串数组:
// 拆分每个参数,工具路径、输入、输出都分开 Process process = Runtime.getRuntime().exec(new String[]{ "cwebp", "/absolute/path/to/input.jpg", "-o", "/absolute/path/to/output.webp" });
如果你的命令里必须用shell特性(比如管道、通配符),可以显式调用shell:
Process process = Runtime.getRuntime().exec(new String[]{ "/bin/sh", "-c", "cwebp /path/input.jpg -o /path/output.webp" });
2. 用绝对路径!绝对路径!绝对路径!
本地Tomcat的工作目录可能和线上不一样:
- 本地你可能是在IDE里启动Tomcat,工作目录是项目根目录
- 线上Tomcat可能是用系统服务启动,工作目录是
/opt/tomcat/bin或者其他目录
哪怕你在代码里用new File("input.jpg").exists()返回true,那也是相对于Java代码的工作目录,但exec执行时的工作目录可能完全不同!所以一定要给所有文件(包括cwebp工具本身)用绝对路径:
- 工具路径:比如
/usr/local/bin/cwebp(可以用which cwebp在服务器上查) - 输入输出文件:通过
ServletContext.getRealPath()获取项目的真实路径,再拼接文件名
3. 检查Tomcat运行用户的权限和环境变量
线上Tomcat一般是用tomcat或者www-data这类低权限用户运行的:
- 环境变量:这些用户的
PATH里可能没有cwebp的路径,所以你直接写cwebp会找不到,必须写绝对路径 - 文件权限:即使文件存在,Tomcat用户有没有读输入文件、写输出文件的权限?比如输入文件放在
/root/upload下,tomcat用户肯定读不了,要把文件移到tomcat有权限的目录(比如/opt/tomcat/webapps/your-project/upload)
4. 检查cwebp的系统依赖
cwebp是编译后的二进制文件,可能依赖系统的动态链接库。本地系统可能已经装了这些库,但线上服务器没装。可以在服务器上执行:
ldd /usr/local/bin/cwebp
看看输出里有没有not found的库,如果有,安装对应的包(比如Ubuntu用apt install libwebp-dev,CentOS用yum install libwebp)
关键提醒:一定要读取进程的错误流
很多时候,Java抛出的“no such file”其实是cwebp自己输出的错误信息,而不是Java层面的问题。比如cwebp找不到输入文件,或者依赖缺失,都会通过错误流输出。一定要开启线程读取错误流,不然进程可能卡死,还看不到真实错误:
// 读取错误流的线程 new Thread(() -> { try (BufferedReader br = new BufferedReader(new InputStreamReader(process.getErrorStream()))) { String line; while ((line = br.readLine()) != null) { System.err.println("cwebp错误输出: " + line); } } catch (IOException e) { e.printStackTrace(); } }).start();
按照这几个步骤排查,应该能解决你的问题!
内容的提问来源于stack exchange,提问作者Secondo

