Java записывает список строк в файл, но файл пуст
Я нашел этот вопрос на других языках, но до сих пор не нашел решение этой проблемы в Java-приложении.
У меня большой .txt
файл с миллионами записей. Каждая запись /n
разграничены. По сути, это один столбец данных из таблицы. Цель состоит в том, чтобы прочитать данные из входного файла и разбить его на части. Затем запишите разделенные данные в новый файл. Например, файл с 2 миллионами записей станет 200 файлами с 10 000 записей в каждом (последний файл содержит <10000).
Я успешно читаю и разбиваю данные. Я успешно создаю первый файл, и он правильно назван.
Проблема только в том, что создан 1 файл, и он пуст. Код as is компилируется и запускается без ошибок и исключений.
Мой код ниже:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
public class ChunkTextFile {
private static final String inputFilename = "inputFile.txt";
public static void main(String[] args) {
BufferedReader reader = null;
BufferedWriter fileWriter = null;
BufferedWriter lineWriter = null;
StringWriter stringWriter = null;
// Create an ArrayList object to hold the lines of input file
List<String> lines = new ArrayList<String>();
try {
// Creating BufferedReader object to read the input file
reader = new BufferedReader(new FileReader("src" + "//" + inputFilename));
// Reading all the lines of input file one by one and adding them into ArrayList
String currentLine = reader.readLine();
while (currentLine != null) {
lines.add(currentLine);
currentLine = reader.readLine();
}
// End of file read.
//Partition ArrayList into a collection of smaller Lists<String>
final AtomicInteger counter = new AtomicInteger(0);
final int size = 10000;
Collection<List<String>> partitioned = lines.stream()
.collect(Collectors.groupingBy(it -> counter.getAndIncrement() / size)).values();
//Printing partitions. Each partition will be written to a file.
//Testing confirms the partitioning works correctly.
partitioned.forEach(System.out::println);
//Iterate through the Collections and create a file for List<String> object.
//Testing confirms that multiple files are created and properly named.
Integer count = 0;
for (List<String> chunks : partitioned) {
// Prepare new incremented file name.
String outputFile = "batched_items_file_";
String txt = ".txt";
count++;
String filename = outputFile + count + txt;
// Write file to directory.
fileWriter = new BufferedWriter(new FileWriter("src" + "//" + outputFile));
fileWriter = new BufferedWriter(new FileWriter(filename));
//Iterate through the List of Strings and write each String to the file.
//Writing is not successful. Only 1 file is created and it is empty.
for (String chunk : chunks) {
stringWriter = new StringWriter();
lineWriter = new BufferedWriter(stringWriter);
// Prepare list of strings to be written to new file.
// Write each item number to file.
lineWriter.write(chunk);
lineWriter.flush();
}
lineWriter.close(); // <- flush the BufferedWriter
fileWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// Closing the resources
System.out.println("Finished");
try {
if (reader != null) {
reader.close();
}
if (fileWriter != null) {
fileWriter.close();
}
if (stringWriter != null) {
stringWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Пример входного файла:
230449
235659
295377
329921
348526
359836
361447
384723
396202
571490
Заранее спасибо.
5 ответов
Вам не нужны все эти дополнительные авторы в for, и автор, который должен записать (fileWriter) в файл, не вызывается. Замените ваш на этот:
for (String chunk : chunks) {
fileWriter.write(chunk);
}
Совет: просто вызовите fileWriter.close() один раз внутри блока finally. Метод close автоматически сбросит программу записи (нет необходимости вызывать fileWriter.flush()).
Есть несколько проблем с вашим кодом. Файлы пусты, потому что вы не закрываете авторов. Вы даже создаете избыточных авторов, как в этой последовательности
fileWriter = new BufferedWriter(new FileWriter("src" + "//" + outputFile));
fileWriter = new BufferedWriter(new FileWriter(filename));
Для оптимальной обработки ресурсов, таких как читатели и писатели, используйте оператор try-with-resources.
Недостающие новые строки - только небольшая проблема.
Кроме того, вы без необходимости читаете весь входной файл в кучную память, просто чтобы иметь возможность выполнить сомнительную операцию потока с ним. Хотя возможно потоковое воспроизведение по файлу напрямую, например с Files.lines
Группировка с AtomicInteger
не является предполагаемым способом использования Stream
тем не мение. И конечный результат все равно будет содержать все входные строки в памяти, в то время как было бы просто записать строки в целевой файл немедленно.
Простое и эффективное решение будет
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class ChunkTextFile {
private static final String inputFilename = "inputFile.txt";
public static void main(String[] args) {
final int size = 10000;
try(BufferedReader reader=Files.newBufferedReader(Paths.get("src", inputFilename))) {
String line = reader.readLine();
for(int count = 0; line != null; count++) {
try(BufferedWriter writer = Files.newBufferedWriter(
Paths.get("batched_items_file_" + count + ".txt"))) {
for(int i = 0; i < size && line != null; i++) {
writer.write(line);
writer.newLine();
line = reader.readLine();
}
}
}
}
catch(IOException ex) {
ex.printStackTrace();
}
}
}
Вы можете использовать только
Path file = Paths.get(filename);
Files.write(file, chunks, Charset.forName("UTF-8"));
И вы должны поставить count=0 перед циклом, иначе он всегда будет 0.
В целом это будет так:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
public class ChunkTextFile {
private static final String inputFilename = "inputFile.txt";
public static void main(String[] args) {
BufferedReader reader = null;
// Create an ArrayList object to hold the lines of input file
List<String> lines = new ArrayList<String>();
try {
// Creating BufferedReader object to read the input file
reader = new BufferedReader(new FileReader(inputFilename));
// Reading all the lines of input file one by one and adding them into ArrayList
String currentLine = reader.readLine();
while (currentLine != null) {
lines.add(currentLine);
currentLine = reader.readLine();
}
// End of file read.
//Partition ArrayList into a collection of smaller Lists<String>
final AtomicInteger counter = new AtomicInteger(0);
final int size = 10;
Collection<List<String>> partitioned = lines.stream()
.collect(Collectors.groupingBy(it -> counter.getAndIncrement() / size)).values();
//Printing partitions. Each partition will be written to a file.
//Testing confirms the partitioning works correctly.
partitioned.forEach(System.out::println);
//Iterate through the Collections and create a file for List<String> object.
//Testing confirms the file is created and properly named.
Integer count = 0;
for (List<String> chunks : partitioned) {
// Prepare new incremented file name.
String outputFile = "batched_items_file_";
String txt = ".txt";
count++;
String filename = outputFile + count + txt;
Path file = Paths.get(filename);
Files.write(file, chunks, Charset.forName("UTF-8"));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// Closing the resources
System.out.println("Finished");
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Я принимаю вышеуказанный ответ, поскольку он решил мою проблему, но я хотел бы расширить его для всех, кто найдет этот вопрос и ответ. Чтобы созданные файлы были в том же формате, что и входной файл (с разделителем новой строки), я изменил свой код, используя принятый ответ, и добавил System.lineSeparator()
,
Окончательное решение выглядит следующим образом.
fileWriter.write(chunk + System.lineSeparator());
Еще раз спасибо за быстрые ответы.
Это рабочая версия. Я рекомендую комментировать или удалять partitioned.forEach(System.out::println);
улучшить производительность.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
public class ChunkTextFile {
private static final String inputFilename = "inputFile.txt";
public static void main(String[] args) {
BufferedReader reader = null;
BufferedWriter fileWriter = null;
// Create an ArrayList object to hold the lines of input file
List<String> lines = new ArrayList<String>();
try {
// Creating BufferedReader object to read the input file
reader = new BufferedReader(new FileReader("src" + "//" + inputFilename));
// Reading all the lines of input file one by one and adding them into ArrayList
String currentLine = reader.readLine();
while (currentLine != null) {
lines.add(currentLine);
currentLine = reader.readLine();
}
// End of file read.
final AtomicInteger counter = new AtomicInteger(0);
final int size = 10000;
Collection<List<String>> partitioned = lines.stream()
.collect(Collectors.groupingBy(it -> counter.getAndIncrement() / size)).values();
//Printing partitions. Each partition will be written to a file.
//Testing confirms the partitioning works correctly.
partitioned.forEach(System.out::println);
//Iterate through the Collections and create a file for List<String> object.
//Testing confirms the file is created and properly named.
Integer count = 0;
for (List<String> chunks : partitioned) {
// Prepare new incremented file name.
String outputFile = "batched_items_file_";
String txt = ".txt";
count++;
String filename = outputFile + count + txt;
// Write file to directory.
fileWriter = new BufferedWriter(new FileWriter("src" + "//" + outputFile));
fileWriter = new BufferedWriter(new FileWriter(filename));
//Iterate through the List of Strings and write each String to the file.
//Writing is not successful. Only 1 file is created and it is empty.
for (String chunk : chunks) {
// Prepare list of strings to be written to new file.
// Write each item number to file.
fileWriter.write(chunk + System.lineSeparator());
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// Closing the resources
System.out.println("Finished");
try {
if (reader != null) {
reader.close();
}
if (fileWriter != null) {
fileWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}