如何使用流读取文件时保留换行符 - java 8

2022-09-04 19:49:02
      try (Stream<String> lines = Files.lines(targetFile)) {  
     List<String> replacedContent = lines.map(line ->  
                                       StringUtils.replaceEach(line,keys, values))
                                       .parallel()
                                       .collect(Collectors.toList());
    Files.write(targetFile, replacedContent);
}

我正在尝试替换文件每行中的多个文本模式。但是我观察到“\r\n”(字节等效的10和13)被替换为“\r”(仅10),我的比较测试失败了。

我想保留换行符在输入文件中的位置,并且不希望java触摸它们。任何人都可以建议是否有一种方法可以做到这一点,而不必使用单独的默认替换“\r\n”。


答案 1

问题是在 之上实现的,它读取一条线,直到行终止符并将其丢弃。然后,当您使用类似 的内容编写行时,这会在每行之后提供系统特定的行终止符,这可能与读入的行终止符不同。Files.lines()BufferedReader.readLine()Files.write()

如果您真的想完全保持行终止符的原样,即使它们是不同行终止符的混合体,也可以使用正则表达式。Scanner

首先定义与包含有效行终止符或 EOF 的行匹配的模式:

Pattern pat = Pattern.compile(".*\\R|.+\\z");

这是一个特殊的换行符匹配器,它与通常的行终止符以及一些我从未听说过的Unicode行终止符相匹配。:-)如果您只想要通常的 CRLFCRLF 终止符,则可以使用类似的东西。\\R(\\r\\n|\\r|\\n)

您必须包含以匹配文件中没有行终止符的潜在最后一行“ 。确保正则表达式始终至少匹配一个字符,以便在扫描程序到达文件末尾时找不到匹配项。.+\\z

然后,使用 a 读取行,直到返回:Scannernull

try (Scanner in = new Scanner(Paths.get(INFILE), "UTF-8")) {
    String line;
    while ((line = in.findWithinHorizon(pat, 0)) != null) {
        // Process the line, then write the output using something like
        // FileWriter.write(String) that doesn't add another line terminator.
    }
}

答案 2

流中的行不包含任何换行符。

如果方法文档提到这一点,那就太好了。但是,如果您遵循实现,它最终会导致.该方法记录为返回行的内容,不包括任何行终止字符Files.lines()BufferedReader.readLine()

您可以在编写行时向行添加换行符。

系统相关的行分隔符由您正在调用的 Files.write() 方法使用,如其同级方法中所述。您还可以使用 System.lineSeparator() 获取此依赖于系统的行分隔符。

如果您想要不同的换行符,并且知道它是什么,则可以指定它。例如:

    try ( PrintStream out = new PrintStream( Files.newOutputStream( targetFile ))) 
    {
        lines.forEach( line -> out.print( line + "\r\n") );
    }

如果需要原始文件的行分隔符,则不能仅依赖去除这些分隔符的方法。选项包括:

  • 读取第一行分隔符,并猜测它在整个文件中是否一致。这允许您继续用于读取行。Files.lines()
  • 使用允许您获取带有分隔符的行的 API。
  • 逐个字符读取,而不是逐行读取,以便可以获取行分隔符。

警告:您的代码从同一文件读取和写入。由于异常终止或错误,您可能会丢失原始数据。