BufferedWriter不会将所有内容写入输出文件

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

细节:程序将一个CSV文本文档转换成SQL命令,将数据插入到一个表中。 该文本文件有超过10000行看起来类似于以下内容:

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

该程序似乎工作正常,除了它只是通过创build一个新的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行之后,但在文件结束之前的几百行。 发生中断的地方在11之间。 但是,字符似乎并不重要,因为如果我将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); } } } 

你需要closures你的OutputStream来清空你的数据的其余部分:

 out.close(); 

BufferedWriter的默认缓冲区大小为8192个字符 ,足以容纳数百行未写入的数据。

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

不再需要时必须closures的资源。

有些人说你必须在调用close()之前先调用flush()来调用BufferedWriter 。 他们错了。 BufferedWriter.close()的文档注意到它“closures了stream,先冲洗它 ”(强调添加)。

logging的冲洗( flush() )的语义是

通过将任何缓冲输出写入基础stream来刷新此stream

所以,你必须closeclose将刷新任何缓冲输出。

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


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

  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 } 

完成写入后,您的代码似乎不会closures写入器。 添加一个out.close() (最好在finally块),它应该正常工作。

你closures你的BufferedWriter.close它在一个finally块

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

不再需要时必须closures的资源。

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

有些事情要考虑:

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

所以,当你完成它们的时候,总是closures你的资源(不仅仅是文件)。

如果你真的想要看一看,大部分Java API的源代码都可用。 BufferedWriter在这里 。

你closures你的BufferedWriter.close它在一个finally块

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

这工作。 我遇到了同样的问题,这对我来说很好运:)

总是closures你的资源(不只是文件),当你完成它们。

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

可能会出现在不closures文件的情况下刷新缓冲区的情况。 在这些情况下,你可以使用flush-method。

既然你使用的是BufferedWriter,你也可以在适当的时候刷新缓冲区:

 out.flush() 

这将把剩余的缓冲区写入到实际的文件中。 closures方法也刷新缓冲区并closures文件。

 out.close() 

可能会出现在不closures文件的情况下刷新缓冲区的情况。 在这些情况下,你可以使用flush-method。

您也可以使用BuffredWriter的换行方法,而不是将\ n添加到行尾。 换行方法使用系统特定的行分隔符,以便您的代码在不同的平台上工作。

 out.newLine() 
Interesting Posts