【问题标题】:Java I/O problem the string was written but didn't show on the fileJava I/O 问题 字符串已写入但未显示在文件中
【发布时间】:2021-10-26 06:28:40
【问题描述】:

我创建了一个 I/O 类来读取一些文本并将其附加到文件中。

我以为它已经写好了,但由于某些原因它没有显示在文件中 - 尽管程序可以识别它。

文件TestResult.csv 位于程序文件夹内的src/main/resources 文件夹中。

我从关于 HowToDoInJava 的教程中学会了如何打开和阅读它:Read a file from the ‘resources’ folder

我的代码

前几行代码与网站中的示例非常相似。

import java.io.*;
import java.nio.file.Files;
import java.io.FileWriter;

public class ReadResourceFileDemo {

    public static void main(String[] args) throws IOException {
        //open file
        ClassLoader classLoader = IOLab.class.getClassLoader();
        File file = new File(classLoader.getResource("TestResult.csv").getFile());

        //append
        try (FileWriter fw=new FileWriter(file, true)) {
            fw.append("\nJulie,Brown,100,A");
            String content = new String(Files.readAllBytes(file.toPath()));
            System.out.println(content);
        }
    }
}

我在TestResult.csv 得到了什么

Alex,Smith,99,A
Jolene,Schmidt,100,A
Mackinzie,Jensen,86,B

目标是将字符串附加到TestResult.csv

在我运行第一次之后,结果是:

Alex,Smith,99,A
Jolene,Schmidt,100,A
Mackinzie,Jensen,86,B

然后我再次运行第二次并得到:

"C:\Program Files\Java\jdk-16.0.2\bin\java.exe" "-javaagent:C:\Program 
Files\JetBrains\IntelliJ IDEA 2021.2.1\lib\idea_rt.jar=56365:C:\Program 
Files\JetBrains\IntelliJ IDEA 2021.2.1\bin" -Dfile.encoding=UTF-8 -classpath 
C:\Users\tuant\IdeaProjects\untitled\target\classes edu.sdccd.cisc191.ReadResourceFileDemo
Alex,Smith,99,A
Jolene,Schmidt,100,A
Mackinzie,Jensen,86,B
Julie,Brown,100,A

Process finished with exit code 0

问题

这意味着程序第一次跳过了追加,或者它跳过了但由于某种原因没有显示在文件中。

当我打开文件 TestResult.csv 时,它只有前 3 行。

但是,手动附加的第 4 行为 Julie,Brown,100,A 没有出现。

非常感谢您的帮助!

【问题讨论】:

  • 很奇怪,你正在读取文件,而你仍然打开它进行写入。你应该移动这个“String content = new String(Files.readAllBytes(file.toPath()));”在 try 语句之外。
  • 写入通过ClassLoader.getResource() 找到的文件是一个非常糟糕的主意。这些应该被视为只读资源,如果您从 jar 文件运行,它们确实是。很容易发生 IDE 的自动后台构建会覆盖该文件和/或您实际上并未打开您认为正在打开的路径!
  • @Tobi:您的教授可能不关心这种情况下的潜在问题。如果是这种情况,那么暂时忽略这个问题。请注意,如果您在“真实代码”中使用这种特定模式,它可能会产生一些绊脚石。
  • @JoachimSauer,这是处理“家庭作业”中的代码挑战的好建议。它鼓励所有学生和像 Tobi 这样的新贡献者诚实并分享背景(例如家庭作业、教授、课程等),以便从专业人士和以前的学生的情境建议和实践经验中受益?? ??️
  • @hc_dev:谢谢。对我来说,这只是对 SO 的一般开放性的扩展:对技术问题的奇怪约束和限制可能来自任何地方,即使在专业软件开发中,我们有时也会遇到周围环境,使“最佳和正确”的解决方案由于某种原因不可行。这就是这份工作的现实(我认为还有许多其他工作)。因此,如果这些存在(因为它是家庭作业,或者某些利益相关者坚持使用 XML 来做某事),那么如果它们被清晰地传达出来就会有所帮助。

标签: java file-io append


【解决方案1】:

发生了什么

当您打开并写入第一次时,它会被写入缓冲区。 此缓冲区在 try-with 块 内维护。但缓冲区尚未刷新。通过显式调用flush() 或关闭由close() 隐式完成的IO-stream/writer 来刷新它:

关闭流,先刷新它。

try 块以右花括号} 结尾时,close 会自动隐式调用。 try-with block 的这种节省资源的态度得益于称为 auto-closable 的概念。 AutoCloseable 接口由大多数 IO-steam 实现,例如 FileWriter

由于您的独立读取操作Files.readAllBytes(file.toPath())也在这个try-with块内,它从磁盘上的文件中读取,而不是从缓冲区中读取。

如何解决

理论上从fw的缓冲区中读取是合乎逻辑的,但这并不容易。

但是,您可以使用 fw.flush() 刷新 try-with 块 内的缓冲区,然后再读取。此刷新将缓冲区写入磁盘,因此您可以从磁盘读取并期望刷新的内容显示为已读取。

或者您可以将读取操作移到 try-with 块 之后,以确保缓冲区之前已刷新和写入。

Epicblood's answer 中建议了这两个修复 - 有点过时但有效。

【讨论】:

  • 感谢您提供的所有信息。我现在有点明白了
【解决方案2】:

尝试在filewriter 上调用flush 方法。

在第一次运行时,可能是缓冲区没有刷新到文件中。一般来说,在写入文件后调用flush 是一个好习惯。

【讨论】:

  • 写操作在设计上不是自动刷新一定是有原因的。这个原因可能是 flushing(磁盘 IO 等)导致的性能。所以也有很好的理由和实践在写入后不调用flush。然而,最后关闭并在关闭之前调用 flush 是一种很好的做法......因此 Java 已经自动化了这一点(请参阅 auto-flush on close 和 auto-closable)。
  • 感谢@hc_dev 指出细微差别。
【解决方案3】:

你需要冲洗你的作家:

try (FileWriter fw=new FileWriter(file, true)) {
    fw.append("\nJulie,Brown,100,A");
    fw.flush();
}
String content = new String(Files.readAllBytes(file.toPath()));
System.out.println(content);

【讨论】:

  • 现在,由于你正在关闭 fw,你不需要刷新它。
  • 感谢您的建议,我会尽快尝试。
  • 它适用于附加问题,但资源文件夹中的 csv 文件未更改。我想有些人说它是只读的。无论如何我们可以处理这个问题吗?
  • @Tobi,我想“它适用于附加问题”的意思是,从更新文件中读取的 content 已打印,即第 4 行 Julie,Brown,100,A 显示在控制台上。如果是这样并且没有发生错误,请打印file.toPath() 在运行时 并检查该位置。它可能在target/classes 文件夹中(运行时您的类路径),而不是src/main/resources。见Updating resource files at runtime
  • 不错!非常感谢@hv_dev
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多