Java 慢速CSV行解析和拆分

Java 慢速CSV行解析和拆分,java,performance,csv,Java,Performance,Csv,我正在尝试解析一个超过100000行的csv,性能问题甚至不允许我在点击“Exception in thread”main“java.lang.OutOfMemoryError:超出GC开销限制”之前到达文件的末尾 有什么不对劲吗,或者我有什么可以改进的地方吗 public static List<String[]> readCSV(String filePath) throws IOException{ List<String[]> csvLine= new A

我正在尝试解析一个超过100000行的csv,性能问题甚至不允许我在点击“Exception in thread”main“java.lang.OutOfMemoryError:超出GC开销限制”之前到达文件的末尾

有什么不对劲吗,或者我有什么可以改进的地方吗

public static List<String[]> readCSV(String filePath) throws IOException{
    List<String[]> csvLine= new ArrayList<String[]>();
    CSVReader reader = new CSVReader(new FileReader(filePath), '\n');
    String[] row;

    while((row = reader.readNext()) != null){
        csvLine.add(removeWhiteSpace(row[0].toString().split(",")));
    }

    reader.close();
    return csvLine;
}

private static String[] removeWhiteSpace(String[] split) {
    for(int index =0; index < split.length;index++){
        split[index] = split[index].trim();
    }
    return split;
}
公共静态列表readCSV(字符串文件路径)引发IOException{
List csvLine=new ArrayList();
CSVReader reader=新的CSVReader(新的文件读取器(文件路径),'\n');
字符串[]行;
while((row=reader.readNext())!=null){
添加(删除空格(行[0].toString().split(“,”));
}
reader.close();
返回csvLine;
}
私有静态字符串[]删除空白(字符串[]拆分){
对于(int index=0;index
将如此大的文件放入内存是一个设计错误。 根据您想做什么,您应该编写一个新的已处理文件,或者将这些行放入dba。 这实现了第一个:

FileInputStream inputStream = null;
Scanner sc = null;
try {
    inputStream = new FileInputStream(path);
    sc = new Scanner(inputStream, "UTF-8");
    while (sc.hasNextLine()) {
        String line = sc.nextLine();
        // System.out.println(line);
    }
    // note that Scanner suppresses exceptions
    if (sc.ioException() != null) {
        throw sc.ioException();
    }
} finally {
    if (inputStream != null) {
        inputStream.close();
    }
    if (sc != null) {
        sc.close();
    }
}

首先,您的内存不足,因为所有行都被添加到列表中

其次,您使用的是String.split(),速度非常慢

第三,不要试图通过编写自己的解析代码来处理CSV,因为这种格式有很多边缘情况(需要处理分隔符、引号等的转义)

解决方案是为此使用库,例如。您应该能够在不到一秒钟的时间内读取一百万行

要进行分析,只需执行以下操作:

public static IterableResult<String[], ParsingContext> readCSV(String filePath) {
    File file = new File(filePath);

    //configure the parser here. By default all values are trimmed
    CsvParserSettings parserSettings = new CsvParserSettings();

    //create the parser
    CsvParser parser = new CsvParser(parserSettings);

    //create an iterable over rows. This will not load everything into memory.
    IterableResult<String[], ParsingContext> rows = parser.iterate(file);

    return rows;
}
public static void main(String... args) throws IOException {
    CsvParserSettings parserSettings = new CsvParserSettings();
    parserSettings.setProcessor(new AbstractRowProcessor() {
        @Override
        public void rowProcessed(String[] row, ParsingContext context) {
            //modify the row data here.
        }
    });

    CsvWriterSettings writerSettings = new CsvWriterSettings();
    CsvRoutines routines = new CsvRoutines(parserSettings, writerSettings);

    FileReader input = new FileReader("c:/path/to/input.csv");
    FileWriter output = new FileWriter("c:/path/to/output.csv");

    routines.parseAndWrite(input, output);
}
希望这有帮助


免责声明:我是这个图书馆的作者。它是开源和免费的(Apache 2.0许可)。

您正试图将整个100000行数据集加载到内存中。将堆大小增加到大于数据集预期大小的值,或更改程序,使其不会一次加载所有数据。不要将整个csv文件存储在程序中。你为什么要读csv?您打算如何处理正在读取的数据?在读取文件时创建对象并计算统计数据,然后擦除对象并继续执行此操作,直到到达csv的末尾。您正在执行哪些统计,以及如何将csv数据转换为对象?是的,问题是您的算法错误。您似乎不需要将所有数据加载到内存中,请重写代码,使其一次处理一行。您可以通过将
for
while
循环组合起来,将内存需求减半:
dividedList.add(删除空格(行[0]。拆分(“,”)这说明了如何实现编写一个新文件?嘿,如果你有时间,我想问一个简单的问题(使用非常好的库),我正在尝试解析CSV1的一行,将其与CSV2的每一行进行比较,然后移动到CSV1的下一行并重复。您是否认为这比使用数据填充对象并执行相同操作的成本更低?CSV1将有100万行。最需要做的是使用
-Xms8G-Xmx8G
运行应用程序,并将两个文件作为列表加载到内存中。然后在内存中对两个列表进行排序,并按顺序运行比较。如果您的数据太大,无法放入内存,您可能可以使用数据库来存储数据。如果没有出路,就采用基于文件的方法。
public static void main(String... args) {
    //this is your output file
    File output = new File("c:/path/to/output.csv");

    //configure the writer if you need to
    CsvWriterSettings settings = new CsvWriterSettings();

    //create the writer. Here we write to a file
    CsvWriter writer = new CsvWriter(output, settings);

    //get the row iterator
    IterableResult<String[], ParsingContext> rows = readCSV("c:/temp");

    try {
        //do whatever you need to the rows here
        for (String[] row : rows) {
            //then write it each one to the output.
            writer.writeRow(row);
        }
    } finally {
        //cleanup
        rows.getContext().stop();
        writer.close();
    }
}
public static void main(String... args) throws IOException {
    CsvParserSettings parserSettings = new CsvParserSettings();
    parserSettings.setProcessor(new AbstractRowProcessor() {
        @Override
        public void rowProcessed(String[] row, ParsingContext context) {
            //modify the row data here.
        }
    });

    CsvWriterSettings writerSettings = new CsvWriterSettings();
    CsvRoutines routines = new CsvRoutines(parserSettings, writerSettings);

    FileReader input = new FileReader("c:/path/to/input.csv");
    FileWriter output = new FileWriter("c:/path/to/output.csv");

    routines.parseAndWrite(input, output);
}