33

I have a Java program that reads some text from a file, line by line, and writes new text to an output file. But not all the text I write to my BufferedWriter appears in the output file after the program has finished. Why is that?

The details: the program takes a CSV text document and converts it into SQL commands to insert the data into a table. The text file has more than 10000 lines which look similar to following:

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

The program seems to work fine except it just stops in the file randomly half way through creating a new SQL statement having printed it into the SQL file. It looks something like:

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

This happens after about 10000 lines but several hundred lines before the end of the file. Where the break happens is between a 1 and a ,. However, the characters doesn't seem important because if I change the 1 to a 42 the last thing written to the new file is 4, which is cutting off the 2 from that integer. So it seems like the reader or writer must just be dying after writing/reading a certain amount.

My Java code is as follows:

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);
        }
    }
}
4

8 回答 8

71

您需要关闭您的OutputStreamwhich 将刷新您的剩余数据:

out.close();

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

于 2012-11-16T23:57:31.333 回答
13

必须 close()你的BufferedWriter. 你必须是close()你的BufferedWriter,因为它是 IS-AWriter并因此实现AutoCloseable,这意味着(强调)它是

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

有人说你必须先打电话flush()给你BufferedWriter,然后再打电话close()。他们错了。文档BufferedWriter.close()说明它“关闭流,首先刷新它”(强调添加)。

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

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

因此,您必须close并且close将刷新任何缓冲的输出。

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


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

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

您还必须closeBufferedReader不再需要它时使用它,因此您应该嵌套 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.

于 2015-01-06T14:04:44.570 回答
7

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

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 在这里

于 2016-02-29T09:58:08.750 回答
5

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

于 2012-11-16T23:58:47.103 回答
5

你努力关闭你的 BufferedWriter.close 它在 finally 块内

   finally {
    out.close();//this would resolve the issue
    }
于 2012-11-16T23:58:56.883 回答
1

使用完资源后,请务必关闭资源(不仅仅是文件)。

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

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

于 2016-08-11T11:36:36.717 回答
0

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

out.flush()

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

out.close()

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

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

out.newLine()
于 2014-11-24T10:40:04.077 回答
-1

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

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

创建 finally 块并将 close 方法放入其中,以便它将所有数据都放入而不会丢失。

 finally {
    out.close();
    }
于 2020-07-04T12:30:21.640 回答