我有一个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);
}
}
}
答案 0 :(得分:63)
答案 1 :(得分:9)
您必须 close()
您的BufferedWriter
。您必须close()
BufferedWriter
,因为它是IS-A Writer
,因此实施AutoCloseable
,这意味着(强调添加)它是
不再需要必须关闭的资源。
有人说在致电BufferedWriter
之前,您必须先为close()
致电flush()
。他们错了。 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
}
答案 2 :(得分:6)
不再需要时必须关闭的资源。
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。
答案 3 :(得分:5)
在您完成写入后,您的代码似乎没有关闭作者。添加out.close()
(最好在最后一个块中),它应该可以正常工作。
答案 4 :(得分:5)
你没有关闭你的BufferedWriter.close它在finally块
中 finally {
out.close();//this would resolve the issue
}
答案 5 :(得分:1)
你没有关闭你的BufferedWriter.close它在finally块
中finally {
out.close();//this would resolve the issue
}
这很有效。我遇到了同样的问题,这对我有用......好运:)
答案 6 :(得分:1)
完成后,请务必关闭资源(而不仅仅是文件)。
finally {
out.close();//this would resolve the issue
}
在某些情况下,您可能需要在不关闭文件的情况下刷新缓冲区。在这些情况下,您可以使用flush-method。
答案 7 :(得分:0)
由于您正在使用BufferedWriter,您还可以在适当的时候刷新缓冲区:
out.flush()
这会将缓冲区的其余部分写入实际文件。 Close-method也会刷新缓冲区并关闭文件。
out.close()
在某些情况下,您可能需要在不关闭文件的情况下刷新缓冲区。在这些情况下,您可以使用flush-method。
您也可以使用BuffredWriter的换行方法,而不是将\ n添加到行尾。 Newline方法使用系统特定的行分隔符,因此您的代码可以在不同的平台上运行。
out.newLine()
答案 8 :(得分:0)
根据文档,调用flush()
方法是没有用的。如果您打算使用FileWriter
,那么flush()
会为您提供帮助。
基本上,在这种情况下,您只需要关闭BufferedWriter.close()
。这将刷新您的其余数据。
创建finally块并将close方法放入其中,以便它将所有数据放入而不会丢失。
finally {
out.close();
}