Java записывает список строк в файл, но файл пуст - PullRequest
0 голосов
/ 22 февраля 2019

Я нашел этот вопрос на других языках, но до сих пор не нашел решения этой проблемы в Java-приложении.

У меня есть большой файл .txt с миллионами записей.Каждая запись /n с разделителями.По сути, это один столбец данных из таблицы.Цель состоит в том, чтобы прочитать данные из входного файла и разбить его на части.Затем запишите разделенные данные в новый файл.Например, файл с 2 миллионами записей станет 200 файлами с 10 000 записей каждый (с последним файлом, содержащим <10000.) </p>

Я успешно читаю и разбиваю данные.Я успешно создаю первый файл, и он правильно назван.

Проблема в том, что создан только 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 ]

0 голосов
/ 22 февраля 2019

Есть несколько проблем с вашим кодом.Файлы пусты, потому что вы не закрываете авторов.Вы даже создаете избыточные средства записи, как в этой последовательности

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();
        }
    }
}
0 голосов
/ 22 февраля 2019

Я принимаю вышеуказанный ответ, поскольку он решил мою проблему, но я хотел бы расширить его для всех, кто найдет этот вопрос и ответ.Чтобы созданные файлы были в том же формате, что и входной файл (с разделителем новой строки), я изменил свой код, используя принятый ответ, и добавил 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();
        }
    }
  }
}
0 голосов
/ 22 февраля 2019

Вам не нужны все эти дополнительные пишущие в вашем for, и писатель, который должен записать (fileWriter) в файл, не вызывается.Замените ваш for на этот:

for (String chunk : chunks) {
    fileWriter.write(chunk);
}

Совет: просто вызовите fileWriter.close () один раз внутри блока finally.Метод close автоматически сбросит программу записи (нет необходимости вызывать fileWriter.flush ()).

0 голосов
/ 22 февраля 2019

Вы можете использовать только

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();
        }
    }
 }
 }
0 голосов
/ 22 февраля 2019

A StringWriter не для записи строк , это для записи в строку .

...