BufferedWriter没有将所有内容写入其输出文件

gol*_*enk 29 java file-io bufferedwriter

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

详细信息:程序采用CSV文本文档并将其转换为SQL命令以将数据插入表中.文本文件超过10000行,类似于以下内容:

2007,10,9,1,1,1006134,19423882
Run Code Online (Sandbox Code Playgroud)

该程序似乎工作正常,除了它只是在文件中随机停止创建一个新的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
Run Code Online (Sandbox Code Playgroud)

这在大约10000行之后发生,但在文件结束之前有几百行.中断发生的地方是a 1和a 之间,.但是,这些字符看起来并不重要,因为如果我将最后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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Rei*_*eus 64

您需要关闭OutputStream将刷新剩余数据的内容:

out.close();
Run Code Online (Sandbox Code Playgroud)

默认缓冲区大小BufferedWriter8192个字符,大到足以轻松容纳数百个不成文的行的数据.

  • @golmschenk - 因为最后几百行仍在缓冲区中...并且在编写器关闭或刷新之前不会写入.这是一个**缓冲的**作家...... (9认同)
  • 事实上,“FileWriter”必须在幕后执行字符集编码,这本身就是一个缓冲操作。如果没有刷新或关闭,默认设置中最多可以有 8192 个待处理字节,即使没有“BufferedWriter”也是如此。由于现在是 2022 年,因此需要指出的是,首选习惯用法是 [try-with-resources 语句](https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html)而不是手动调用“close()”。 (2认同)

Rae*_*ald 10

必须 close()你的BufferedWriter.你必须close()你的BufferedWriter,因为它是-A Writer,因此工具AutoCloseable,这意味着(强调)是

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

有人说,你必须先调用flush()BufferedWriter之前调用close().他们错了.它的文档BufferedWriter.close()"关闭流,首先刷新它 "(强调添加).

flushing(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
 }
Run Code Online (Sandbox Code Playgroud)

您还必须closeBufferedReader当它是不再需要的,所以你应该嵌套的try-与资源块:

 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
 }
Run Code Online (Sandbox Code Playgroud)

  • 您不需要嵌套“try”语句;一个“try”语句支持多个资源。`try(BufferedReader in = ...; BufferedWriter out = ...) { ... } catch(IOException ex) { ... }` (3认同)

Jai*_*tel 6

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

finally {
    out.close();//this would resolve the issue
    }
Run Code Online (Sandbox Code Playgroud)

有些事情需要考虑:

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

因此,当您完成它们时,请始终关闭您的资源(而不仅仅是文件).

如果你真的想要了解一下,大多数Java API的源代码都是可用的.BufferedWriter就在这里.


Ian*_*rts 5

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


Per*_*ror 5

你将你的BufferedWriter.close关闭在finally块中

   finally {
    out.close();//this would resolve the issue
    }
Run Code Online (Sandbox Code Playgroud)