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()