Java 以可读格式将巨大的ArrayList写入文件

Java 以可读格式将巨大的ArrayList写入文件,java,arraylist,filewriter,large-data,Java,Arraylist,Filewriter,Large Data,我有一个程序,可以处理来自传感器系统的大量传感器数据。我目前正在研究将程序的输出写入一个文本文件,这样我就可以检查程序是否正确地处理了输出 现在,我正在ArrayList之前写入一些标识符,然后使用ArrayList.toString将ArrayList写入文件 输出文件总共包含21行,ArrayList的大小从100项到400.000项不等。使用toString方法,我通常使用的任何文件编辑程序都无法打开文件并检查它们 我想对ArrayList中的项进行一个小处理: String lineTo

我有一个程序,可以处理来自传感器系统的大量传感器数据。我目前正在研究将程序的输出写入一个文本文件,这样我就可以检查程序是否正确地处理了输出

现在,我正在ArrayList之前写入一些标识符,然后使用ArrayList.toString将ArrayList写入文件

输出文件总共包含21行,ArrayList的大小从100项到400.000项不等。使用toString方法,我通常使用的任何文件编辑程序都无法打开文件并检查它们

我想对ArrayList中的项进行一个小处理:

String lineToWrite = "";

String arrayListString = "\n";
for(String s : sensorLine){
    arrayListString += "\t" + s + "\n";
}

lineToWrite = identifer1 + ";" + identifier2 + ";" + arrayListString;
但对于一些足够大的ArrayList来说,这似乎需要永远的时间。是否有人有更好/更快的方法来执行此操作,或者知道一个好的文件查看程序

我使用了以下方法,但没有以下问题:

记事本++->打开缓慢,完全打开后会变慢 升华文本3->打开速度非常慢! 作为传感器数据的一个小提示:我总共有230万个传感器输入

编辑1: 为了扩展这个问题,我可能需要补充一点,那就是将庞大的数组拆分为单个字符串的部分被证明是一个问题。该程序在数组上的迭代速度非常慢,因为它只是在每次遍历时增加arrayListString的大小,我想这会占用大量内存/处理能力

编辑2: 至于编写方法本身,我使用的是一个BufferedWriter,带有实际方法变量的占位符:

output = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename, toAppend), "UTF-8"));
对于我正在使用的实际写作:

output.append(line)
output.flush();

问题是,您正在将一个非常大的字符串组装到内存中,然后一次将其全部写入,需要引导大量的字符串操作,从而为每个字符串分配内存

相反,请考虑使用流。使用Writer,您可以迭代数组并在运行时附加到文件,这将快得多

以下是一个很好的基础教程:


至于编辑器问题,大多数编辑器要么将整个文件加载到内存中,要么将其以行或字节块的形式加载。如果您有大量的行,您可能需要重新检查您的格式。

我认为您必须将数据分割成块,并在需要时加载到编辑器中。下面是一个很好的答案。 将数据转储到数据库中

然后你可以做一些有趣的事情,比如选择数字1000-1100,或者搜索值,在数据库客户端(比如Toad)中执行avg/min/max

SQL查询语言应该不是问题。客户也不是


Java有嵌入式独立数据库;H2可能就足够了。

出于某种奇怪的原因,几乎所有的文本编辑器在您排长队时都会非常慢。通常,您可以轻松编辑一个有一百万行的文件,但如果该文件包含一行100000个字符,则会遇到问题

关于编写文件的性能,有几个权衡

写入较大的数据块通常有利于提高性能。也就是说:当你想写1000个字节时,你应该一次写这1000个字节,而不是一个接一个地写。但在本例中,您正试图通过组合一个巨大的字符串来构建一个真正巨大的数据块。这可能会造成回击并降低性能,因为由于许多字符串串联,组装此字符串的成本可能会很高

因此,逐行写入文件可能是一个合理的折衷方案:块仍然足够大以补偿一般写入操作的工作量,并且仍然足够小以避免字符串连接开销

例如:使用BufferedWriter写入100万行的时间很难测量:

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class ArrayListToFile
{
    public static void main(String[] args) throws IOException
    {
        List<String> sensorLine = new ArrayList<String>();
        int size = 1000000;
        Random random = new Random(0);
        for (int i=0; i<size; i++)
        {
            sensorLine.add(String.valueOf(random.nextDouble()));
        }

        write("out.txt", sensorLine);
    }

    private static void write(String fileName, Iterable<?> elements)
        throws IOException
    {
        try (BufferedWriter bw = new BufferedWriter(
            new OutputStreamWriter(new FileOutputStream(fileName))))
        {
            String identifier1 = "i1";
            String identifier2 = "i2";

            bw.write(identifier1 + ";" + identifier2 + ";\n");

            for (Object s : elements)
            {
                bw.write("\t" + s + "\n");
            }
        }
    }
}

最后我找到了解决办法

我使用了StringBuilder来解决向文件中写入巨大字符串的问题。方法如下:

StringBuilder sb = new StringBuilder();
for(String s : arrayList){
    sb.append("\t" + s + "\n"
}

String line = identifier1 + ";" + identfier2 + ";" + sb.toString();

对于编辑来说,Sublime Text 3似乎不太在意,只要行长度不超过40万个字符

+是一个可怕的主要性能杀手,我不认为它是否被StringBuilder有效地取代。你是否考虑过数据流?写的速度快百倍。这是我的方法,但是我现在需要验证数据在进入数据库存储之前经过的算法。这就是将其存储到文件中的原因。无论如何谢谢你的建议!:我真的很喜欢你的建议,把传感器线和其他数据分开写。我不确定它是否比我目前的方法快。我和一个架线工一起去的。计算一个我只需写一次的字符串元素总量似乎真的很快。可以,StringBuilder在某些情况下可以避免大量字符串连接开销。然而,有一点需要考虑的是,当你没有40万B时 ut 4亿行,您可能会在某个时候耗尽内存。以流式方式单独写入行,这样可以更好地扩展。但是,当您当前的解决方案适合您时,就可以了。
StringBuilder sb = new StringBuilder();
for(String s : arrayList){
    sb.append("\t" + s + "\n"
}

String line = identifier1 + ";" + identfier2 + ";" + sb.toString();