【问题标题】:Schrodinger's bug, BufferedWriter doesn't write into TXT unless manually checked薛定谔的bug,BufferedWriter不写入TXT除非手动检查
【发布时间】:2015-07-10 07:15:09
【问题描述】:

我是一名新手程序员,想成为一名程序员,遇到了这个我找不到答案的问题。
我使用Eclipse,对于程序我使用slicklwjgl-2.9.3
以下代码处于状态,在 public void update(...)

这部分代码有问题:
(file.txt 存在且名称中没有大写字母,giveToFile 是一个字符串)(不抛出异常)

try{
    BufferedWriter bw = new BufferedWriter(new FileWriter("src/file.txt"));
    bw.write(giveToFile);
    bw.close();
}catch(IOException e){
    e.printStackTrace();
}

(编辑:

try{
    bw = new BufferedWriter(new FileWriter("src/file.txt"));
    bw.write(giveToFile);
    bw.flush();
}catch(IOException e){
    e.printStackTrace();
}finally {
    if (bw != null){
        try {
           bw.close();
       }catch (Throwable t){
           t.printStackTrace();
       }
   }
}  

产生了同样的错误)

我在try块的最后放置了一个System.out.print,它运行正常,而且只运行一次。我还使用了 g.drawStringgiveToFile 总是给出预期的字符串。我执行了以下两个实验。 (这个程序是一个游戏式的东西,你在最后根据你的表现得到一个分数,它把它放在高分中,然后重写 TXT 文件。)(我建议之前阅读 TLDR。)

实验1(file.txt:“0 0 0 0 0”)(成功):

  1. 我运行程序并获得 15 分。
    - 从 txt 加载的字符串:“0 0 0 0 0”
    - giveToFile(字符串):“15 0 0 0 0"
  2. 我双击左侧 Eclipse 中的 TXT 文件(包资源管理器),它在新选项卡中打开,我在 txt 中看到:“15​​ 0 0 0 0”,我关闭选项卡
  3. 我再次运行程序并获得 30 分。
    - 从文本引导的字符串:“15 0 0 0 0”
    - giveToFile(字符串):“30 15 0 0 0"
  4. 我双击左侧 Eclipse 中的 TXT 文件(包资源管理器),它在新选项卡中打开,我在 txt 中看到:“30 15 0 0 0”,我关闭选项卡
  5. 我最后一次运行程序并获得 0 分。
    - 从 txt 加载的字符串:“30 15 0 0 0”
    - giveToFile(字符串): "30 15 0 0 0"

实验2(file.txt:“0 0 0 0 0”)(失败):

  1. 我运行程序并获得 15 分。
    - 从 txt 加载的字符串:“0 0 0 0 0”
    - giveToFile(字符串):“15 0 0 0 0"
  2. 我双击左侧 Eclipse 中的 TXT 文件(包资源管理器),它在新选项卡中打开,我在 txt 中看到:“15​​ 0 0 0 0”,我关闭选项卡
  3. 我再次运行程序并获得 30 个 ponts。
    - 由文本引导的字符串:“15 0 0 0 0”
    - giveToFile(字符串):“30 15 0 0 0"
  4. 我没有双击 TXT 文件,我没有在新选项卡中打开它,也没有检查它。
  5. 我最后一次运行程序并获得 0 分。
    - 从 txt 加载的字符串:“15 0 0 0 0”
    - giveToFile(字符串): “15 0 0 0 0”

TLRD:除非我手动检查,否则程序不会写入 TXT 文件

有bug,也没有,取决于我是否检查txt文件

很抱歉这个问题很长,如果它是超级简单的东西,很抱歉,但我是初学者,在互联网上找不到任何解决方案,提前感谢您的帮助

编辑:

我用这个来关闭程序:(xpos和ypos是鼠标坐标)(基本上是一个原始的退出按钮)

if((xpos>= 200 && xpos <= 400) && (ypos>=100 && ypos <=200)){
    if(Mouse.isButtonDown(0)){
        System.exit(0);
    }
}  

我得到了这个:(没有例外)

2015 年 4 月 30 日星期四 16:44:14 CEST 信息:Slick Build #237
2015 年 4 月 30 日星期四 16:44:14 CEST 信息:LWJGL 版本:2.9.3
2015 年 4 月 30 日星期四 16:44:14 CEST 信息:OriginalDisplayMode:1366 x 768 x 32 @60Hz
2015 年 4 月 30 日星期四 16:44:14 CEST 信息:目标显示模式:600 x 600 x 0 @0Hz
2015 年 4 月 30 日星期四 16:44:15 CEST 信息:开始显示 600x600
2015 年 4 月 30 日星期四 16:44:15 CEST 信息:使用 Java PNG 加载器 = true
2015 年 4 月 30 日星期四 16:44:15 CEST 信息:控制器不可用

这部分读取文件,没有其他部分对文件做任何事情,阅读器工作正常:

try{
    InputStream is = getClass().getResourceAsStream("/file.txt");
    Scanner fileIn = new Scanner(is);
    for(int i=0; i<SCOREMAX; i++){
        scoreInt[i] = fileIn.nextInt();
    }
    fileIn.close();
}catch (Exception e) {
    e.printStackTrace();
}  

它在 public void init 内,SCOREMAX 的类型是public static final int

【问题讨论】:

  • bw.close();之前你累了吗bw.flush();
  • @BrettWalker close 调用 flush
  • 根据您提供的数据,我最好的猜测是,您在 Eclipse 上打开的(旧)副本配置为在程序执行后自动同步到文件系统。这会将磁盘上的文件副本反转为旧版本(您打开的版本)。要验证您可能根本不想打开文件并多次运行该程序。如果可行,您可以运行程序并检查文件副本上的每次迭代(简单地手动复制)。如果两者都有效,我会倾向于我的观察。
  • @Reut Sharabani BufferdWriter 的 close 方法刷新它的内部缓冲区,但它不会在底层 Writer 上调用 flush。
  • @Reut Sharabani 我只打开了 Eclipse,并且只从 Eclipse 中打开了 file.txt(它在 Eclipse 中的新选项卡中显示),file.txt 从未在单独的窗口中弹出。没有在 Eclipse 中打开它,只是运行了几次程序,写的都不行。

标签: java eclipse lwjgl slick bufferedwriter


【解决方案1】:

您需要在 finally 块中 close BufferedWriter

您也可以在完成写入后在try 块中flushBufferedWriter,尽管close 操作将首先刷新它。

这是一个重新审视的例子,Java 6 风格:

BufferedWriter bw = null;

try {
    bw = new BufferedWriter(new FileWriter("src/file.txt"));
    bw.write(giveToFile);
    // bw.flush(); // if needed
}
catch(IOException e){
    e.printStackTrace();
}
finally {
    if (bw != null) {
        try {
            bw.close();
        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }
}

... 和 Java 7 风格(“try with”和AutoClosables):

try (BufferedWriter bw = new BufferedWriter(new FileWriter("src/file.txt"))) {
    bw.write(giveToFile);
    bw.flush();
}
catch(IOException e){
    e.printStackTrace();
}

【讨论】:

  • close 应该调用flush。另外,如果没有抛出异常,那它是否在finally 中又有什么关系呢?
  • @ReutSharabani 如前所述,close 调用将 flush。但是,OP 可能出于某种原因急切地想要flush,因此可以选择。
  • @ReutSharabani 关于finally 块,无论Exceptions 是否抛出,它都会执行,因此close 流在那里的常见做法。 Java 7 的 AutoClosables 赋予了更流畅的语法。
  • 为什么这样可以解决问题?为什么连续两次调用flush(没有写入新数据时)很重要?你能把我和“急切的冲洗”问题联系起来吗?我熟悉 finally 并且 OP 明确表示没有抛出异常 - 这意味着 close 被调用。这是我不清楚的答案。
  • @ReutSharabani 我知道没有“急切冲洗”问题。但是您可能需要以编程方式确保数据在磁盘上,这是通过刷新来完成的,要么懒惰地(让BufferedWriter 执行它或等待close),要么急切地(DIY)。
【解决方案2】:

耶!!!在尝试了你们所说的一切之后,深入研究这个话题,花了将近 2 天的时间研究我找到解决方案的问题!!!!

该文件仍然在同一个src,所以它的路径是src/file.txt,但是在bin文件夹中自动创建了一个同名文件,删除一个结果两个文件都被删除。总之,这两个文件在某种程度上是一样的

对于我用来读取文件的代码:

try{    
    InputStream is = state1.class.getResourceAsStream("/file.txt");

    Scanner fileIn = new Scanner(is);
    for(int i=0; i<SCOREMAX; i++){
        scoreInt[i] = fileIn.nextInt();
    }
    fileIn.close();
}catch (Exception e) {
     e.printStackTrace();
}  

请注意,我没有使用 src/file.txt 只是 /file.txt,它从 bin 文件夹中的文件中读取。

对于我使用的写作:

FileOutputStream fs = null;
try{
    fs = new FileOutputStream("bin/file.txt");
    OutputStreamWriter ow = new OutputStreamWriter(fs);
    BufferedWriter bw = new BufferedWriter(ow);
    bw.write(giveToFile);
    bw.flush();
    bw.close();
}catch (IOException e){
    e.printStackTrace();
}finally{
    try{fs.close();} catch(IOException e){e.printStackTrace();}
}  

再一次,请注意我在这里也没有使用src/file.txt,而是将它定向到bin 文件夹中的文件。

成功了!!!

最后,我在 /* ... */ 中得到了大约 70 行代码,标记为“//几乎可以工作”,并且至少是我已经删除的 10 倍。但终于成功了!!

感谢所有在这里评论和回答的人,没有你们,我将无法找到解决方案。再次感谢大家!

【讨论】:

  • 所以主要原因似乎确实是@ReutSharabani 在他的评论stackoverflow.com/questions/29970216/… 中提到的(我稍后提到),即以编程方式更新src 文件夹中的内容会混淆Eclipses 本地历史
【解决方案3】:

Java 区分文件和资源。资源在类路径上,可能在 jar 中。因此,资源应该被认为是只读的。它也可能被缓存。

在您的情况下,使用资源(阅读时)是不可取的。

我会做如下的事情。

String userDir = System.getProperty("user.home");
Path txtPath = Paths.get(userDir, "file.txt");

List<String> content = Files.readAllLines(txtPath, StandardCharsets.UTF_8);

Files.write(txtPath, content, StandardCharsets.UTF_8);

giveToFile = content.get(0);
content = Collections.singletonList(giveToFile);

这使文件远离类路径,因此您可以在 jar 中创建应用程序。

您可以维护一个初始只读 file.txt 作为资源,用作初始模板,并将其复制到用户目录。

我这里使用的是UTF-8编码,所以文件格式是可移植的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-19
    • 1970-01-01
    • 1970-01-01
    • 2018-08-26
    相关资源
    最近更新 更多