Вопрос-ответ

BufferedWriter not writing everything to its output file

BufferedWriter не все записывает в свой выходной файл

У меня есть 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 строк, но за несколько сотен строк до конца файла. Разрыв происходит между a 1 и a ,. Однако символы не кажутся важными, потому что, если я изменю 1 на a 42, последнее, что записывается в новый файл, будет 4, что отсекает 2 от этого целого числа. Таким образом, кажется, что reader или writer, должно быть, просто умирает после записи / считывания определенного объема.

Мой 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);
}
}
}
Переведено автоматически
Ответ 1

Вам нужно закрыть ваш OutputStream который удалит оставшуюся часть ваших данных:

out.close();

Размер буфера по умолчанию для BufferedWriter составляет 8192 символа, что достаточно велико, чтобы легко вместить сотни строк неписаных данных.

Ответ 2

Вы должны close() свой BufferedWriter. Вы должны close() свой BufferedWriter, потому что это-A Writer и, таким образом, реализует AutoCloseable, что означает (выделено мной), что это


Ресурс, который должен быть закрыт, когда он больше не нужен.


Некоторые люди говорят, что вы должны сначала вызвать flush() для своего BufferedWriter перед вызовом close(). Они ошибаются. В документации для BufferedWriter.close() отмечается, что он "Закрывает поток, сначала очищая его" (выделено мной).

Документированная семантика flushing (flush()) такова


Очищает этот поток, записывая любой буферизованный вывод в базовый поток


Итак, вы должны close, и close очистит любой буферизованный вывод.

Ваш выходной файл не включает весь текст, который вы записали в свой BufferedWriter потому что он сохранил часть этого текста в буфере. The BufferedWriter никогда не очищал этот буфер, передавая его в файл, потому что вы никогда не говорили ему об этом.


Начиная с Java 7, лучший способ гарантировать, что AutoCloseable ресурс, такой как BufferedWriter, закрыт, когда в нем больше нет необходимости, - это использовать автоматическое управление ресурсами (ARM), также известное как попытка с ресурсами:

 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
}

Не поддавайтесь искушению (как предполагают другие ответы здесь) просто вызвать close() в конце вашего метода, когда ваш код "закончен" с использованием writer. Это не сработает, если ваш код записи выдает исключение, и, в частности, если он выдает IOException.

Ответ 3

Ресурс, который должен быть закрыт, когда он больше не нужен.


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

Некоторые моменты, которые следует учитывать:


  • BufferedWriter.close() сбрасывает буфер в базовый поток, поэтому, если вы забудете это сделать flush() и не закроете, в вашем файле может оказаться не весь текст, который вы в него записали.

  • BufferedWriter.close() также закрывает обернутый файл записи. Когда это FileWriter, это в конечном итоге закроет FileOutputStream и сообщит ОС, что вы закончили запись в файл.

  • Сборщик мусора автоматически вызовет close() не BufferedWriter или обернутый FileWriter, а FileOuputStream . Таким образом, ОС будет довольна, но вам придется дождаться GC.

  • Однако вы всегда хотите освободить ресурсы ОС, как только они вам больше не нужны. Это касается открытых файлов, подключений к базе данных, очередей печати ... чего угодно. Поверьте мне в этом.

  • BufferedWriter.close() очищает внутренний символьный буфер, так что память будет доступна для сборки мусора, даже если сам BufferedWriter остается в области видимости.

Итак, всегда закрывайте свои ресурсы (не только файлы), когда вы закончите с ними.

Если вы действительно хотите заглянуть под обложку, доступна большая часть исходных текстов Java API. BufferedWriter находится здесь.

Ответ 4

Похоже, что ваш код не закрывает программу записи после того, как вы закончили запись в него. Добавьте out.close() (предпочтительно в блоке finally), и он должен работать должным образом.

java