使用Java ProcessBuilder将主机文件夹复制到Docker容器失败(错误码1)
问题排查与解决
1. 先拿到错误详情(最核心的一步)
你现在的代码只读取了命令的标准输出,但错误码1对应的报错信息是在标准错误流里的,根本没打印出来,这是没法排查的关键问题。先改代码把错误信息打出来:
简便方法:合并错误流到标准输出
ProcessBuilder processBuilder = new ProcessBuilder(); processBuilder.command("docker", "cp", "./cassandra/.", "cassandra:/cassandra/"); processBuilder.redirectErrorStream(true); // 把错误输出合并到标准输出一起打印 try { Process process = processBuilder.start(); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { System.out.println(line); // 现在会显示错误信息了 } int exitCode = process.waitFor(); assertThat(exitCode).as("copy cassandra folder from host to cassandra container").isZero(); } catch (Exception e) { Assertions.fail("Failed to Initialize cassandra db", e); }
更严谨的方法:单独读取错误流
如果怕输出混淆,可以开线程分别读标准输出和错误输出,避免阻塞:
ProcessBuilder processBuilder = new ProcessBuilder(); processBuilder.command("docker", "cp", "./cassandra/.", "cassandra:/cassandra/"); try { Process process = processBuilder.start(); // 读标准输出 new Thread(() -> { try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { String line; while ((line = reader.readLine()) != null) { System.out.println("输出:" + line); } } catch (IOException e) { e.printStackTrace(); } }).start(); // 读错误输出 new Thread(() -> { try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) { String line; while ((line = reader.readLine()) != null) { System.err.println("错误:" + line); // 这里会显示具体报错 } } catch (IOException e) { e.printStackTrace(); } }).start(); int exitCode = process.waitFor(); assertThat(exitCode).as("copy cassandra folder from host to cassandra container").isZero(); } catch (Exception e) { Assertions.fail("Failed to Initialize cassandra db", e); }
运行后就能看到具体报错,比如“找不到源路径”,这直接指向问题根源。
2. 最常见的原因:工作目录不匹配
ProcessBuilder默认用JVM启动时的工作目录,这个目录大概率和你在终端执行命令的目录不一样。比如你终端是在项目根目录跑的docker命令,但Java程序可能是在target目录、IDE的临时目录启动的,导致./cassandra/.找不到。
解决方法:给ProcessBuilder指定明确的工作目录,就是你在终端执行命令时所在的路径:
// 替换成你实际的项目根目录路径,比如"/home/xxx/your-project" File workingDir = new File("/path/to/your/project-root"); processBuilder.directory(workingDir);
如果是Maven/Gradle项目,也可以用System.getProperty("user.dir")获取启动时的工作目录,但注意IDE运行和打包后运行的路径可能不同,最好用绝对路径更稳妥。
其他可能的小问题
- 权限差异:Java程序运行的用户没加入docker组,而终端用户是有权限的。可以检查运行Java的用户是否在docker组里,或者直接用docker的绝对路径(比如
/usr/bin/docker)执行命令。 - 路径写法问题:有些系统下
./cassandra/.的写法可能被ProcessBuilder解析异常,换成./cassandra(不带末尾的/.)或者绝对路径试试。
总结
先打错误信息,90%的概率是工作目录不对导致源路径找不到,按上面的步骤排查基本能解决。
内容的提问来源于stack exchange,提问作者user468587
相关产品推荐
相关产品推荐

