用于在运行时

时间:2017-03-23 14:17:23

标签: java android arrays csv data-structures

是否有一种聪明的方式来创建类似JSON的'字符串结构 - 浮点对,'键'不需要因为数据将被随机抓取 - 尽管从0-n增加的密钥可能有助于随机检索相关数据。由于数据集的大小(10k对值),我需要将其保存到外部文件类型。

原因是我的数据将如何编译。为了节省手动输入数据的人员,该项目将基于excel,保存为CSV,使用临时java程序解析为文件格式(例如jJSON),可以将其添加到我的项目资源文件夹中。然后我可以从这个集合中检索数据,而我的应用程序不必在创建应用程序时手动将巨大的数组加载到内存中。我可以很容易地将CSV解析为“填充”#39;运行时的数组(或类似的) - 但我担心在移动设备上,内存开销会很大吗?

我已经审核了Suitable Java data structure for parsing large data fileData structure options for efficiently storing sets of integer pairs on disk?的答案,但未能得出明确的结论。

我已经尝试保存到.JSON文件,但不确定我是否可以请求随机条目,另外这对于保持简单的结构来说似乎相当麻烦。是一个treeMap或哈希表,我需要集中搜索。

要为我的查询提供一些上下文,我的应用程序将在android上运行,并且需要引用一个定义(大约500个字符的字符串)和一个转换因子(一个Float)。我需要检索随机数据条目。用户在会话期间只能发出2或3个请求 - 因此在将10k元素数组加载到内存中时没有意义。 QUERY:Android手机上潜在的现代技术很容易通过这种类型的查询,如果我在运行时分析数百万条目,它可能只是一个问题?

如果这将提供所需的功能,我愿意使用SQLlite来保存我的数据。请注意,数据集必须来自excel(CSV,TXT等)的易于导出的文件格式。

非常感谢您给我的任何建议。

1 个答案:

答案 0 :(得分:1)

这是一种可能的设计,在提供快速访问的同时需要最小的内存占用:

以逗号分隔或制表符分隔值的数据文件开头,这样您就可以在数据对之间换行。

保留一组long值,这些值对应于数据文件中行的索引。当您知道线条的位置时,可以使用InputStream.skip()前进到所需的线条。这充分利用了skip()通常比read InputStream快一点的事实。

你会有一些设置代码在初始化时运行以索引行。

增强功能是仅对每个 n 行进行索引,以使数组更小。因此,如果 n 为100并且您正在访问第1003行,则将第10个索引跳到第1000行,然后读取另外两行以转到第1003行。这样您就可以调整使用较少内存的数组大小。

我认为这是一个有趣的问题,所以我整理了一些代码来测试我的想法。它使用了一个样本4MB CSV文件,我从一些拥有大约36K行数据的大数据网站下载。大多数线都超过100个字符。

以下是设置阶段的代码段:

    long start = SystemClock.elapsedRealtime();

    int lineCount = 0;
    try (InputStream in = getResources().openRawResource(R.raw.fl_insurance_sample)) {

        int index = 0;
        int charCount = 0;
        int cIn;
        while ((cIn = in.read()) != -1) {
            charCount++;

            char ch = (char) cIn;  // this was for debugging
            if (ch == '\n' || ch == '\r') {
                lineCount++;
                if (lineCount % MULTIPLE == 0) {
                    index = lineCount / MULTIPLE;
                    if (index == mLines.length) {
                        mLines = Arrays.copyOf(mLines, mLines.length + 100);
                    }
                    mLines[index] = charCount;
                }
            }

        }

        mLines = Arrays.copyOf(mLines, index+1);

    } catch (IOException e) {
        Log.e(TAG, "error reading raw resource", e);
    }

    long elapsed = SystemClock.elapsedRealtime() - start;

我发现我的数据文件实际上是由回车符而不是换行符分隔的。它必须是在Apple计算机上创建的。因此,'\r'以及'\n'的测试。

以下是访问该行的代码片段:

                long start = SystemClock.elapsedRealtime();

                int ch;
                int line = Integer.parseInt(editText.getText().toString().trim());
                if (line < 1 || line >= mLines.length ) {
                    mTextView.setText("invalid line: " + line + 1);
                }
                line--;
                int index = (line / MULTIPLE);
                in.skip(mLines[index]);
                int rem = line % MULTIPLE;
                while (rem > 0) {
                    ch = in.read();
                    if (ch == -1) {
                        return; // readLine will fail
                    } else if (ch == '\n' || ch == '\r') {
                        rem--;
                    }
                }

                BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                String text = reader.readLine();

                long elapsed = SystemClock.elapsedRealtime() - start;

我的测试程序使用了EditText,因此我可以输入行号。

为了让您对性能有所了解,第一阶段平均大约1600ms来读取整个文件。我使用了MULTIPLE值10.访问文件中的最后一条记录平均大约30毫秒。

我认为,只需29312字节的内存占用就可以实现30ms的访问速度。

你可以see the sample project on GitHub