【问题标题】:BufferedWriter not writing everything to its output fileBufferedWriter 没有将所有内容写入其输出文件
【发布时间】:2012-11-05 17:48:52
【问题描述】:

我有一个 Java 程序,它逐行从文件中读取一些文本,并将新文本写入输出文件。但在程序完成后,并不是我写给BufferedWriter 的所有文本都出现在输出文件中。这是为什么呢?

详细信息:程序获取一个 CSV 文本文档并将其转换为 SQL 命令以将数据插入到表中。该文本文件有 10000 多行,类似于以下内容:

2007,10,9,1,1,1006134,19423882

该程序似乎工作正常,只是它只是在创建新 SQL 语句并将其打印到 SQL 文件的过程中随机停止在文件中。它看起来像:

insert into nyccrash values (2007, 1, 2, 1, 4, 1033092, 259916);
insert into nyccrash values (2007, 1, 1, 1, 1, 1020246, 197687);
insert into nyccrash values (2007, 10, 9, 1

这发生在大约 10000 行之后,但在文件末尾之前几百行。中断发生在1, 之间。但是,这些字符似乎并不重要,因为如果我将1 更改为42,则写入新文件的最后一件事是4,它会从该整数中删除2。所以看起来读者或作家一定是在写/读了一定量之后就死了。

我的Java代码如下:

import java.io.*;

public class InsertCrashData
{
    public static void main (String args[])
    {
        try
        {   
            //Open the input file.
            FileReader istream = new FileReader("nyccrash.txt");
            BufferedReader in = new BufferedReader(istream);
            //Open the output file.
            FileWriter ostream = new FileWriter("nyccrash.sql");
            BufferedWriter out = new BufferedWriter(ostream);
            String line, sqlstr;

            sqlstr = "CREATE TABLE nyccrash (crash_year integer, accident_type integer, collision_type integer, weather_condition integer, light_condition integer, x_coordinate integer, y_coordinate integer);\n\n"; 
            out.write(sqlstr);

            while((line = in.readLine())!= null)
            {
                String[] esa = line.split(",");
                sqlstr = "insert into nyccrash values ("+esa[0]+", "+esa[1]+", "+esa[2]+", "+esa[3]+", "+esa[4]+", "+esa[5]+", "+esa[6]+");\n";
                out.write(sqlstr);
            }
        }
        catch(Exception e)
        {
            System.out.println(e);
        }
    }
}

【问题讨论】:

    标签: java file-io bufferedwriter


    【解决方案1】:

    您需要关闭您的 OutputStream,这将刷新您的剩余数据:

    out.close();
    

    BufferedWriter 的默认缓冲区大小为8192 characters,大到足以轻松容纳数百行未写入的数据。

    【讨论】:

    • @golmschenk - 因为最后几百行仍在缓冲区中......并且在编写器关闭或刷新之前不会被写入。它是一个缓冲 writer ...
    【解决方案2】:

    必须close()你的BufferedWriter。你必须close()你的BufferedWriter,因为它是Writer,因此实现了AutoCloseable,这意味着(强调)它是

    当不再需要时必须关闭的资源

    有人说您必须先为您的BufferedWriter 调用flush(),然后才能调用close()。他们错了。 BufferedWriter.close() 的文档指出它“关闭流,先刷新它”(强调添加)。

    已记录的刷新语义 (flush()) 是

    通过将任何缓冲输出写入底层流来刷新此流

    因此,您必须close,而close 将刷新所有缓冲的输出。

    您的输出文件不包含您写入BufferedWriter 的所有文本,因为它在缓冲区中存储了一些文本。 BufferedWriter 从未清空该缓冲区,将其传递给文件,因为您从未告诉它这样做。


    从 Java 7 开始,确保 AutoCloseable 资源(例如 BufferedWriter)在不再需要时关闭的最佳方法是使用自动资源管理 (ARM),也称为 try-with-resources

     try (BufferedWriter out = new BufferedWriter(new FileWriter(file))) {
        // writes to out here
     } catch (IOException ex) {
        // handle ex
     }
    

    当您不再需要它时,您还必须 close 您的 BufferedReader,因此您应该嵌套 try-with-resources 块:

     try (BufferedReader in = new BufferedReader(new FileReader("nyccrash.txt")) {
        try (BufferedWriter out = new BufferedWriter(new FileWriter("nyccrash.sql"))) {
           // your reading and writing code here
        }
     } catch (IOException ex) {
        // handle ex
     }
    

    当您的代码使用编写器“完成”时,不要被诱惑(正如这里的其他答案所建议的那样)只是在方法结束时调用close()。如果您编写的代码抛出异常,特别是如果它抛出 IOException,这将不起作用。

    【讨论】:

      【解决方案3】:

      不再需要时必须关闭的资源。

      finally {
          out.close();//this would resolve the issue
          }
      

      需要考虑的一些事项:

      • BufferedWriter.close() 将缓冲区刷新到底层流,因此如果您忘记 flush() 并且不关闭,您的文件可能没有您写入的所有文本。
      • BufferedWriter.close() 也会关闭包装好的 Writer。当它是 FileWriter 时,这将最终关闭 FileOutputStream 并告诉操作系统您已完成对文件的写入。
      • 垃圾收集器将自动调用close(),不是在BufferedWriter 或包装的FileWriter 上,而是在FileOuputStream 上。所以操作系统会很高兴,但你必须等待 GC。
      • 但是,您总是希望在不再需要操作系统资源时立即释放它们。这适用于打开的文件、数据库连接、打印队列……任何东西。相信我这个。
      • BufferedWriter.close() 确实清除了内部字符缓冲区,以便内存可用于垃圾收集,即使 BufferedWriter 本身仍在范围内。

      因此,当您完成资源(而不仅仅是文件)时,请务必关闭它们。

      如果您真的想一探究竟,大多数 Java API 的源代码都是可用的。 BufferedWriter 是here

      【讨论】:

        【解决方案4】:

        完成写入后,您的代码似乎并未关闭编写器。添加out.close()(最好在 finally 块中)它应该可以正常工作。

        【讨论】:

        • 我无法理解为什么在关闭bufferedWritter 之前没有将输出写入文件。请你好心教我为什么会这样
        • @KasunSiyambalapitiya 如果你是close() BufferedWriter 那么剩余的输出将被刷新到文件中,这个问题的问题是BufferedWriter 永远不会被关闭,所以一些输出仍留在内部缓冲区中,不会写入底层文件流。
        【解决方案5】:

        你必须关闭你的 BufferedWriter。在 finally 块中关闭它

           finally {
            out.close();//this would resolve the issue
            }
        

        【讨论】:

        • 我无法理解为什么在关闭bufferedWritter 之前没有将输出写入文件。请你好心教我为什么会这样
        【解决方案6】:

        当您使用完资源(而不仅仅是文件)时,请务必关闭它们。

         finally {
            out.close();//this would resolve the issue
            }
        

        您可能希望在不关闭文件的情况下刷新缓冲区。在这些情况下,您可以使用 flush-method。

        【讨论】:

          【解决方案7】:

          由于您使用的是 BufferedWriter,因此您还可以在适当的时候刷新缓冲区:

          out.flush()
          

          这会将缓冲区的其余部分写入实际文件。关闭方法也会刷新缓冲区并关闭文件。

          out.close()
          

          您可能希望在不关闭文件的情况下刷新缓冲区。在这些情况下,您可以使用 flush-method。

          您也可以使用 BuffredWriter 的换行方法,而不是在行尾添加 \n。 Newline-method 使用系统特定的行分隔符,因此您的代码可以在不同的平台上运行。

          out.newLine()
          

          【讨论】:

            【解决方案8】:

            根据文档,调用flush() 方法是没有用的。如果您打算使用FileWriter,那么flush() 会帮助您。

            基本上在这种情况下,您只需要关闭BufferedWriter.close()。这将刷新您的剩余数据。

            创建 finally 块并将 close 方法放入其中,这样它就可以将所有数据都放好。

             finally {
                out.close();
                }
            

            【讨论】:

              猜你喜欢
              • 2011-11-17
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-11-29
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多