运行Dart Shelf Docker容器时出现FileSystemException异常
问题根因
报错的核心原因是相对路径的解析规则和多阶段构建的工作目录不继承问题:
- 你代码里写的
File('my_data.json')是相对路径,Dart会以*程序启动时的当前工作目录(CWD)*为基准找文件,不是以可执行文件所在的目录为基准。 - 你的Dockerfile用了多阶段构建,第一阶段
dart:stable里设置的WORKDIR /app只在构建阶段生效,第二阶段用scratch作为运行镜像时,默认工作目录是根目录/,且你没有手动设置工作目录,所以程序启动后会去找/my_data.json,但你实际把文件复制到了/app/my_data.json,路径不匹配就会报文件不存在。
可选解决方法
任选一种方案修改即可:
- 方案1:在运行阶段指定工作目录(改动最小)
在scratch阶段的配置里新增WORKDIR /app,把容器启动后的工作目录切到/app,和你存放文件、可执行文件的目录对齐,相对路径就能正常解析。
修改后的运行阶段Dockerfile配置:FROM scratch COPY --from=build /runtime/ / COPY --from=build /app/bin/server /app/bin/ COPY my_data.json /app/my_data.json # 新增工作目录配置 WORKDIR /app EXPOSE 8080 CMD ["/app/bin/server"] - 方案2:代码里写死基于可执行文件位置的绝对路径(最稳妥,不依赖容器配置)
不要依赖工作目录,直接通过Dart提供的API拿到可执行文件的位置,再拼接json文件的绝对路径,不管从什么目录启动程序都能找到文件。
修改Dart读取文件的代码:
如果你觉得路径跳级麻烦,也可以把Dockerfile里的json复制路径改成import 'dart:io'; import 'dart:convert'; // 获取当前可执行文件的所在目录 final exePath = Platform.resolvedExecutable; final exeDir = File(exePath).parent.path; // 可执行文件在/app/bin目录下,json在/app目录,所以向上跳一级拼接路径 final jsonFullPath = '$exeDir/../my_data.json'; final _data = json.decode(File(jsonFullPath).readAsStringSync()) as List<dynamic>;COPY my_data.json /app/bin/my_data.json,对应代码里的路径直接写$exeDir/my_data.json即可。 - 方案3:把json文件复制到容器默认工作目录(不推荐,不好管理)
容器默认工作目录是根目录/,你可以直接把json复制到根目录匹配相对路径:# 替换原有的COPY my_data.json行 COPY my_data.json /my_data.json
排查技巧
如果修改后仍有问题,可以按以下步骤定位:
- 临时把Dockerfile的CMD改成
CMD ["ls", "-R", "/"],启动容器后会打印整个容器的文件列表,直接确认my_data.json的实际存放路径。 - 在Dart代码里加一行
print(Directory.current.path),启动后看程序实际的工作目录是什么,和文件路径对比就能找到偏差。
内容的提问来源于stack exchange,提问作者R2T8
相关产品推荐
相关产品推荐

