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行之后,但在文件结束之前的几百行。 发生中断的地方在1和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); } } }
你需要closures你的OutputStream来清空你的数据的其余部分:
out.close();
BufferedWriter的默认缓冲区大小为8192个字符 ,足以容纳数百行未写入的数据。
你必须 close()你的BufferedWriter 。 你必须close()你的BufferedWriter因为它是一个Writer ,因此实现了AutoCloseable ,这意味着(强调增加)它是
不再需要时必须closures的资源。
有些人说你必须在调用close()之前先调用flush()来调用BufferedWriter 。 他们错了。 BufferedWriter.close()的文档注意到它“closures了stream,先冲洗它 ”(强调添加)。
logging的冲洗( flush() )的语义是
通过将任何缓冲输出写入基础stream来刷新此stream
所以,你必须close , close将刷新任何缓冲输出。
您的输出文件不包含您写入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()