首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >文件是在Windows上读取而不是在Linux容器上读取?

文件是在Windows上读取而不是在Linux容器上读取?
EN

Stack Overflow用户
提问于 2020-08-07 04:15:43
回答 1查看 157关注 0票数 2

正如标题所说,当在linux容器上运行相同的代码时,我无法读取文件(csv文件)的内容

代码语言:javascript
复制
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,如下所示:

代码语言:javascript
复制
var vehicleConfigurations = Files.lines(file)
            .map(line -> build(line, codeType))
            .collect(Collectors.toCollection(HashSet::new));

但这有一个关于内容的问题(仅在容器上)。它会读取文件,但不是整个文件,它会读到给定行(比如8000行),但不会完全读取(在逗号分隔符之前读取大约半行)。然后我得到了一个java.lang.ArrayIndexOutOfBoundsException,因为我的build方法试图拆分然后行,然后我访问索引1(它没有索引1,只有0):

代码语言:javascript
复制
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文件中的卷复制的,如下所示:

代码语言:javascript
复制
    volumes:
  - ./file-sources:/file-sources

然后,我将文件(在linux容器上使用cp命令)从文件源复制到/root,因为这是应用程序侦听新文件到达的位置。然后使用我描述的方法读取文件内容。示例文件数据(没有奇怪的字符):

提前谢谢。

更新:尝试newBufferedReader方法,同样的结果(适用于windows,不适用于linux容器):

代码语言:javascript
复制
  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配置的原因?

EN

回答 1

Stack Overflow用户

发布于 2020-08-07 04:42:51

在java中有一些你永远不应该使用的方法。永远不会。

new FileReader(File)就是其中之一。

任何时候,你有一个表示字节的东西,不知何故,字符或字符串掉出来了,反之亦然?永远不要使用这些,除非上述方法的规范明确指出它总是使用预先设置的字符集。几乎所有这样的方法都使用“系统默认字符集”,这意味着操作取决于运行它的机器。这是“这将会失败,你的测试不会捕捉到它”的简写。这是你不想要的。

这就是为什么你永远不应该使用这些东西。

FileReader已经修复了(还有第二个接受字符集的构造函数),但那是从JDK11开始的。你已经有了很好的新API,为什么还要切换回旧的文件API呢?别干那事。

文件中的所有不同方法,比如Files.newBufferedReader,都被指定为UTF-8,如果不指定的话(这样,文件更有用,而且不像大多数其他java核心库)。因此:

代码语言:javascript
复制
try (BufferedReader br = Files.newBufferedReader(file)) {

这只是..。更好..。而不是你的台词。

现在,它可能仍然会在你身上失败。但这很好!它也会在你开发机器上失败。实际上,您正在读取的文件很可能不是UTF_8格式的。这是可能的猜测;大多数linuxen都是使用UTF_8默认字符集部署的,而大多数开发机器不是;如果您的开发机器正在工作,而您的部署环境不是,那么显而易见的结论就是您的输入文件不是UTF_8。它也不需要是您的开发机器有默认设置的文件;像ISO_8859_1这样的东西永远不会抛出异常,但它将读取官样文章。您的代码可能看起来正常(没有崩溃),但您读取的文本仍然是不正确的。

找出您得到的文本编码,然后指定它。如果是ISO_8859_1,例如:

代码语言:javascript
复制
try (BufferedReader br = Files.newBufferedReader(file, StandardCharsets.ISO_8859_1)) {

现在你的代码不再有“在某些机器上工作,但在另一些机器上不能工作”的性质。

如果有必要,可以在十六进制编辑器中检查失败的行。我敢打赌,一定会有一个字节是0x80或更高(十进制,128或更高)。在各种文本编码中,从ASCII到任何ISO-8859变体,从UTF-8 Windows Cp1252到macroman到许多其他的东西,所有的一切都倾向于完全相同的东西,所以只要它都是普通的字母和数字,错误的编码不会有任何不同。但是,一旦达到0x80或更高,它们都是不同的。有了这个字节+一些关于它应该是什么字符的知识,通常可以很好地开始找出文本文件采用的是什么编码。

注意:如果不是这样,请检查文本文件是如何从开发机器复制到部署环境的。你确定这是同一个文件吗?如果它是通过文本机制复制的,字符集编码也是罪魁祸首,但这一次是如何写入文件,而不是你的java应用程序如何读取它。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63291140

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档