用Java读取CSV文件的最快方法

Far*_*deh 5 java csv performance android

我注意到java.util.Scanner在读取大文件时使用非常慢(在我的例子中是CSV文件).

我想改变我目前正在阅读文件的方式,以提高性能.以下是我目前的情况.请注意,我正在为Android开发:

InputStreamReader inputStreamReader;
    try {
        inputStreamReader = new InputStreamReader(context.getAssets().open("MyFile.csv"));
        Scanner inputStream = new Scanner(inputStreamReader);
        inputStream.nextLine(); // Ignores the first line
        while (inputStream.hasNext()) {
            String data = inputStream.nextLine(); // Gets a whole line
            String[] line = data.split(","); // Splits the line up into a string array

            if (line.length > 1) {
                // Do stuff, e.g:
                String value = line[1];
            }
        }
        inputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
Run Code Online (Sandbox Code Playgroud)

使用Traceview,我设法发现主要的性能问题,特别是:java.util.Scanner.nextLine()java.util.Scanner.hasNext().

我已经看过其他问题了(比如这个),我遇到过一些CSV读者,比如Apache Commons CSV,但他们似乎没有太多关于如何使用它们的信息,而且我是不知道他们会多快多少.

我也听说过使用FileReaderBufferedReader像回答这一个,但同样,我不知道改进是否会显著.

我的文件大约有30,000行,并且使用我目前的代码(上图),从大约600行读取值至少需要1分钟,所以我没有时间读取值需要多长时间从超过2,000行下来,但有时,在阅读信息时,Android应用程序变得无法响应并崩溃.

虽然我可以简单地更改部分代码并亲自查看,但我想知道是否有更快的替代方法,我没有提及,或者我是否应该使用FileReaderBufferedReader.将大文件拆分成较小的文件会更快,并根据我想要检索的信息选择要读取的文件吗?最好,我也想知道为什么最快的方法是最快的(即什么使它快).

Jer*_*kes 5

uniVocity 解析器拥有最快的 CSV 解析器(比 OpenCSV 快 2 倍,比 Apache Commons CSV 快 3 倍),具有许多独特的功能。

这是一个关于如何使用它的简单示例:

CsvParserSettings settings = new CsvParserSettings(); // many options here, have a look at the tutorial

CsvParser parser = new CsvParser(settings);

// parses all rows in one go
List<String[]> allRows = parser.parseAll(new FileReader(new File("your/file.csv")));
Run Code Online (Sandbox Code Playgroud)

为了加快流程,您可以选择您感兴趣的列:

parserSettings.selectFields("Column X", "Column A", "Column Y");
Run Code Online (Sandbox Code Playgroud)

通常,您应该能够在 2 秒左右解析 400 万行。通过列选择,速度将提高大约 30%。

如果您使用RowProcessor ,它会更快。有许多开箱即用的实现,用于处理对象、POJOS 等的转换。文档解释了所有可用功能。它是这样工作的:

// let's get the values of all columns using a column processor
ColumnProcessor rowProcessor = new ColumnProcessor();
parserSettings.setRowProcessor(rowProcessor);

//the parse() method will submit all rows to the row processor
parser.parse(new FileReader(new File("/examples/example.csv")));

//get the result from your row processor:
Map<String, List<String>> columnValues = rowProcessor.getColumnValuesAsMapOfNames();
Run Code Online (Sandbox Code Playgroud)

我们还建立了一个简单的速度对比的项目在这里


Cir*_*zzo 3

您的代码适合加载大文件。但是,当操作的时间比您预期的长时,最好在任务中而不是在 UI 线程中执行它,以防止响应能力不足。

AsyncTask 类有助于做到这一点:

private class LoadFilesTask extends AsyncTask<String, Integer, Long> {
    protected Long doInBackground(String... str) {
        long lineNumber = 0;
        InputStreamReader inputStreamReader;
        try {
            inputStreamReader = new
                    InputStreamReader(context.getAssets().open(str[0]));
            Scanner inputStream = new Scanner(inputStreamReader);
            inputStream.nextLine(); // Ignores the first line

            while (inputStream.hasNext()) {
                lineNumber++;
                String data = inputStream.nextLine(); // Gets a whole line
                String[] line = data.split(","); // Splits the line up into a string array

                if (line.length > 1) {
                    // Do stuff, e.g:
                    String value = line[1];
                }
            }
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return lineNumber;
    }

    //If you need to show the progress use this method
    protected void onProgressUpdate(Integer... progress) {
        setYourCustomProgressPercent(progress[0]);
    }

    //This method is triggered at the end of the process, in your case when the loading has finished
    protected void onPostExecute(Long result) {
        showDialog("File Loaded: " + result + " lines");
    }
}
Run Code Online (Sandbox Code Playgroud)

...并执行为:

new LoadFilesTask().execute("MyFile.csv");
Run Code Online (Sandbox Code Playgroud)