gpt4 book ai didi

java - 在 Windows 上读取文件但在 Linux 容器上不读取?

转载 作者:行者123 更新时间:2023-12-01 14:13:08 25 4
gpt4 key购买 nike

就像标题说的那样,在 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,因为这是应用程序正在监听新文件到达的地方。然后使用我描述的方法读取文件内容。示例文件数据(没有奇怪的字符):
file contents
提前致谢。
更新:尝试使用 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 个配置的原因?

最佳答案

java中有一些你永远不应该使用的方法。曾经。new FileReader(File)是其中之一。
任何时候你有一个东西代表字节并且以某种方式出现字符或字符串,反之亦然?永远不要使用这些,除非所述方法的规范明确指出它总是使用预设的字符集。几乎所有此类方法都使用“系统默认字符集”,这意味着该操作取决于您运行它的机器。这是“这将失败,您的测试无法捕捉到它”的简写。你不想要的。
这就是为什么你永远不应该使用这些东西。
FileReader 已被修复(有第二个构造函数接受一个字符集),但这只是从 JDK11 开始。您已经有了不错的新 API,为什么要切换回极旧的 File API?不要那样做。
Files中的所有各种方法,例如Files.newBufferedReader , 如果您不指定,则指定执行 UTF-8(这样,Files 更有用,并且与大多数其他 java 核心库不同)。因此:

try (BufferedReader br = Files.newBufferedReader(file)) {
这只是..比你的线更好。
现在,它可能仍然会失败。但这很好!它会 还有在您的开发机器上失败。实际上,您正在阅读的文件很可能不是 UTF_8 格式的。这是可能的猜测;大多数 linuxen 使用 UTF_8 默认字符集部署,而大多数开发机器没有;如果您的开发机器正在工作而您的部署环境没有,那么明显的结论是您的输入文件不是 UTF_8。它也不需要是您的开发机器的默认设置;像 ISO_8859_1 这样的东西永远不会抛出异常,但它会改为读取 gobbledygook。您的代码似乎可以工作(没有崩溃),但您阅读的文本仍然不正确。
找出你得到的文本编码,然后指定它。如果是 ISO_8859_1,例如:
try (BufferedReader br = Files.newBufferedReader(file, StandardCharsets.ISO_8859_1)) {
现在您的代码不再具有“适用于某些机器但不适用于其他机器”的性质。
如果必须,请在十六进制编辑器中检查失败的行。我敢打赌, donut 里会有一个 0x80 或更高的字节(十进制,128 或更高)。在各种文本编码中,从 ASCII 到任何 ISO-8859 变体到 UTF-8 Windows Cp1252 到 macroman 再到许多其他东西,直到并包括 127 在内的所有内容往往意味着完全相同的东西,只要它只是纯字母和数字,编码错误不会有任何区别。但是一旦你达到 0x80 或更高,它们就完全不同了。有了那个字节+对它应该是什么字符的一些知识,通常是弄清楚该文本文件的编码是什么的一个好的开始。
注意:如果不是这样,请检查文本文件是如何从您的开发机器复制到您的部署环境的。你确定是同一个文件?如果它是通过文 native 制复制的,那么字符集编码又可能是罪魁祸首,但这一次是文件的写入方式,而不是你的 java 应用程序读取它的方式。

关于java - 在 Windows 上读取文件但在 Linux 容器上不读取?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63291140/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com