Java命令在Node.js子进程exec中执行失败,命令行运行正常
Node.js子进程调用Java命令时遭遇POI文件无效错误的解决思路
最近我遇到一个头疼的问题:用Node.js的child_process.execSync执行一条处理Excel的Java命令,明明在终端直接跑完全正常,但通过Node调用就报错说文件不是有效的OOXML文件。具体情况如下:
我的命令与调用方式
要执行的Java命令:
java -Duser.dir=/app/system/controllers/ -jar -Xmx2048m -XX:-UseGCOverheadLimit "/app/system/controllers/validation/dist/Validation.jar" "load" "ATC" "/app/system/controllers/validation/test files/uploadedfile1.xlsx" "/app/system/controllers/validation/test files/uploadedfile2.xlsx"
Node.js调用代码:
var exec = require('child_process').execSync; var child = exec('java -Duser.dir=/app/system/controllers/ -jar -Xmx2048m -XX:-UseGCOverheadLimit "/app/system/controllers/validation/dist/Validation.jar" "load" "ATC" "/app/system/controllers/validation/test files/uploadedfile1.xlsx" "/app/system/controllers/validation/test files/uploadedfile2.xlsx"', function (error, stdout, stderr){ if(error){ console.log("The error is: ",error); } });
遇到的错误信息
Error: Command failed: java -Duser.dir=/app/system/controllers/ -jar -Xmx2048m -XX:-UseGCOverheadLimit "/app/system/controllers/validation/dist/Validation.jar" "load" "ATC" "/app/system/controllers/validation/test files/uploadedfile1.xlsx" "/app/system/controllers/validation/test files/uploadedfile2.xlsx" Exception in thread "main" org.apache.poi.openxml4j.exceptions.NotOfficeXmlFileException: No valid entries or contents found, this is not a valid OOXML (Office Open XML) file at org.apache.poi.openxml4j.opc.ZipPackage.getPartsImpl(ZipPackage.java:290) at org.apache.poi.openxml4j.opc.OPCPackage.getParts(OPCPackage.java:774) at org.apache.poi.openxml4j.opc.OPCPackage.open(OPCPackage.java:344) at org.apache.poi.util.PackageHelper.open(PackageHelper.java:37) at org.apache.poi.xssf.usermodel.XSSFWorkbook.<init>(XSSFWorkbook.java:285)
问题原因与解决方法
核心原因:字符串参数的shell解析问题
当你把整个命令拼成一个字符串传给execSync时,Node会把这个字符串交给系统shell去分词解析。虽然你给带空格的文件路径加了双引号,但有时候shell的解析规则(或者Node对字符串的转义处理)会导致路径被错误拆分,Java程序实际收到的是不完整的文件路径,自然读不出正确的Excel内容,触发POI的无效文件错误。而直接在终端执行时,shell能正确识别引号里的空格路径,所以一切正常。
最优解决:使用数组形式传递参数
避免shell解析的坑,最好的办法是把每个命令参数拆分成数组的元素,这样Node会直接把参数传递给Java进程,不需要经过shell处理,带空格的路径也能被正确识别。
修改后的代码如下:
const { execSync } = require('child_process'); try { // 把每个参数单独作为数组元素,无需加引号 const result = execSync('java', [ '-Duser.dir=/app/system/controllers/', '-jar', '-Xmx2048m', '-XX:-UseGCOverheadLimit', '/app/system/controllers/validation/dist/Validation.jar', 'load', 'ATC', '/app/system/controllers/validation/test files/uploadedfile1.xlsx', '/app/system/controllers/validation/test files/uploadedfile2.xlsx' ]); console.log('执行结果:', result.toString()); } catch (error) { console.error('执行出错:', error.message); console.error('错误详情:', error.stderr.toString()); }
额外排查建议
- 检查文件权限:确认Node进程运行的用户拥有这两个Excel文件的读取权限(比如如果是web服务器进程,可能和你终端用户的权限不同)。
- 验证文件存在性:可以在Node代码里用
fs.existsSync()先检查文件路径是否正确,比如:const fs = require('fs'); console.log(fs.existsSync('/app/system/controllers/validation/test files/uploadedfile1.xlsx')); // 应该返回true
内容的提问来源于stack exchange,提问作者Sal
相关产品推荐
相关产品推荐

