【发布时间】:2020-08-06 20:15:42
【问题描述】:
正如标题所说,在 linux 容器上运行相同代码时,我无法读取文件(csv 文件)的内容
private Set<VehicleConfiguration> loadConfigurations(Path file, CodeType codeType) throws IOException {
log.debug("File exists? " + Files.exists(file));
log.debug("Path " + file.toString());
log.debug("File " + file.toFile().toString());
log.debug("File absolute path " + file.toAbsolutePath().toString());
String line;
Set<VehicleConfiguration> configurations = new HashSet<>(); // this way we ignore duplicates in the same file
try(BufferedReader br = new BufferedReader(new FileReader(file.toFile()))){
while ((line = br.readLine()) != null) {
configurations.add(build(line, codeType));
}
}
log.debug("Loaded " + configurations.size() + " configurations");
return configurations;
}
日志返回“true”和两个系统中的文件路径(本地在 windows 和 linux docker 容器上)。在 Windows 上它加载“15185 个配置”,但在容器上它加载“0 个配置”。
该文件存在于linux上,我使用bash并自己检查。我使用head命令,文件有行。
在此之前,我尝试使用 Files.lines,如下所示:
var vehicleConfigurations = Files.lines(file)
.map(line -> build(line, codeType))
.collect(Collectors.toCollection(HashSet::new));
但这有一个关于内容的问题(仅在容器上)。它读取文件而不是整个文件,它到达给定的行(例如第 8000 行)并且没有完全读取它(在逗号分隔符之前读取大约半行)。然后我得到一个 java.lang.ArrayIndexOutOfBoundsException 因为我的构建方法尝试拆分然后行并且我访问索引 1(它没有,只有 0):
private VehicleConfiguration build(String line, CodeType codeType) {
String[] cells = line.split(lineSeparator);
var vc = new VehicleConfiguration();
vc.setVin(cells[0]);
vc.setCode(cells[1]);
vc.setType(codeType);
return vc;
}
可能是什么问题?我不明白相同的代码(在 Java 中)如何在 Windows 上工作,但在 Linux 容器上却不行。没有意义。
我使用的是 Java 11。文件是使用 docker-compose 文件中的卷复制的,如下所示:
volumes:
- ./file-sources:/file-sources
然后我将文件(在 linux 容器上使用 cp 命令)从文件源复制到 /root,因为这是应用程序监听新文件到达的地方。然后使用我描述的方法读取文件内容。示例文件数据(没有奇怪的字符):
提前致谢。
更新:尝试使用 newBufferedReader 方法,结果相同(适用于 windows,不适用于 linux 容器):
private Set<VehicleConfiguration> loadConfigurations(Path file, CodeType codeType) throws IOException {
String line;
Set<VehicleConfiguration> configurations = new HashSet<>(); // this way we ignore duplicates in the same file
try(BufferedReader br = Files.newBufferedReader(file)){
while ((line = br.readLine()) != null) {
configurations.add(build(line, codeType));
}
}
log.debug("Loaded " + configurations.size() + " configurations");
return configurations;
}
linux 容器中的 wc -l(在 /root 中)返回:15185 hard_001.csv
更新:这不是解决方案,但我发现通过将文件直接放在文件源文件夹中并使该文件夹成为代码侦听的文件夹,文件被读取。所以基本上,在容器内使用 cp/mv 到另一个文件夹时,问题似乎更加明显。也许文件在完全复制/移动之前被读取,这就是它读取 0 个配置的原因?
【问题讨论】:
-
docker容器中的文件是空的吗?文件如何复制到容器中?读取的代码运行时文件是否有可能没有完全写入?
-
就像我在主帖中所说的那样。它不是空的。我使用 head/cat/ 命令通过在容器上运行 bash 来检查它是否为空。该文件是从容器中的另一个文件夹复制的。它与 docker-compose 卷一起放在原始文件夹中。
-
文件是从另一个文件夹复制的 - 这是什么时候/如何发生的?
-
特别是,我看不出所呈现的代码如何记录加载的 0 个配置,除非它正在读取的文件完全为空。否则,
BufferedReader将至少读取一行,否则会引发异常,如果是前者,则build()将提供至少一个配置对象,否则自身会引发异常。方法中的任何地方都没有catch块,因此如果抛出任何异常,则不会到达最后一个log.debug()。 -
附带说明,当您的参数是
Path时,您应该使用Files.newBufferedReader(Path…)而不是通过new BufferedReader(new FileReader(file.toFile()))强制使用默认文件系统。
标签: java docker stream java-stream bufferedreader