简体   繁体   English

Java将字符串列表写入文件,但是文件为空

[英]Java writing a list of strings to a file, but the file is empty

I have found this question in other languages, but have yet to find a solution to this issue in a java application. 我已经用其他语言找到了这个问题,但是还没有在Java应用程序中找到解决此问题的方法。

I have a large .txt file with millions of records. 我有一个大型的.txt文件,其中包含数百万条记录。 Each record is /n delimited. 每个记录都用/n分隔。 Basically it is a single column of data from a table. 基本上,它是表中的单列数据。 The goal is to read the data from the input file and partition it. 目的是从输入文件中读取数据并对其进行分区。 Then write the partitioned data to a new file. 然后将分区数据写入新文件。 For example, a file with 2 million records will become 200 files with 10,000 records each (with the last file containing <10,000.) 例如,一个具有200万个记录的文件将变为200个文件,每个记录具有10,000个记录(最后一个文件包含<10,000个)。

I am successfully reading and partitioning the data. 我已成功读取和分区数据。 I am successfully creating the first file and it is being named properly. 我已经成功创建了第一个文件,并且文件名正确。

The problem is only 1 file is created and it is empty. 问题是只有1个文件被创建并且为空。 The code as is compiles and runs without errors or exceptions. 代码按原样编译并运行,没有错误或异常。

My code is below: 我的代码如下:

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

Input file example: 输入文件示例:

230449
235659
295377
329921
348526
359836
361447
384723
396202
571490

Thank you in advance. 先感谢您。

You don't need all those extra writers in your for and the writer supposed to write (fileWriter) to the file is not being called. 您不需要所有for多余的编写器,并且不会调用本应写入文件(fileWriter)的编写器。 Replace your for by this one: 用这个替换您的:

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

Tip: Just call fileWriter.close() once inside the finally block. 提示:只需在finally块内调用一次fileWriter.close()即可。 The close method will automatically flush the writer for you (there's no need to call fileWriter.flush()). close方法将自动为您刷新编写器(无需调用fileWriter.flush())。

There are several issues with your code. 您的代码有几个问题。 The files are empty, because you don't close the writers. 文件为空,因为您没有关闭编写器。 You are even creating redundant writers as in this sequence 您甚至按照以下顺序创建多余的编写器

fileWriter = new BufferedWriter(new FileWriter("src" + "//" + outputFile));
fileWriter = new BufferedWriter(new FileWriter(filename));

To handle resources like readers and writers in the optimal way, use the try-with-resources statement . 要以最佳方式处理诸如读者和作家之类的资源,请使用try-with-resources语句

The missing new lines is only a small problem. 缺少新行只是一个小问题。

Further, you are unnecessarily reading the entire input file into the heap memory, just to be able to perform a questionable Stream operation on it. 此外,您不必要将整个输入文件读入堆存储器,只是为了对其执行可疑的Stream操作。 While it is possible to stream over a file directly, eg with Files.lines , the grouping with an AtomicInteger is not the intended way of using a Stream anyway. 尽管可以直接在文件Files.lines传输(例如,使用Files.lines ,但使用AtomicInteger进行分组并不是使用Stream的预期方式。 And the end result would still hold the entire input lines in memory while it would be straight-forward to write the lines to the target file immediately. 最终结果仍将整个输入行保留在内存中,而直接将这些行立即写入目标文件则很简单。

A simple and efficient solution would be 一个简单而有效的解决方案是

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

StringWriter不是用于编写字符串 ,而是用于写入字符串

You can use just 你可以用

Path file = Paths.get(filename);
Files.write(file, chunks, Charset.forName("UTF-8"));

And, you should put count=0 before loop, otherwise it will be always 0. 并且,应将count = 0放在循环之前,否则它将始终为0。

Overall it will be like this: 总的来说,它将是这样的:

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

I am accepting the above answer as it solved my problem, but I wanted to expand on it for anyone that finds this question and answer. 我接受了以上答案,因为它解决了我的问题,但我想为发现此问题和答案的任何人扩展此答案。 For the created files to be in the same format as the input file (newline delimited) I changed my code using the accepted answer and added System.lineSeparator() . 为了使创建的文件与输入文件具有相同的格式(以换行符分隔),我使用可接受的答案更改了代码,并添加了System.lineSeparator()

The final solution looks like this. 最终的解决方案如下所示。

fileWriter.write(chunk + System.lineSeparator());

Thank you again for the quick responses. 再次感谢您的快速回复。

This is the working version. 这是工作版本。 I recommend commenting out or removing partitioned.forEach(System.out::println); 我建议注释掉或删除partitioned.forEach(System.out::println); to improve performance. 提高性能。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM