有没有一种聪明的方法来创建String的“类似于JSON”的结构-浮点对,不需要“键”,因为数据将被随机捕获-尽管从0-n递增的键可能有助于随机检索关联的数据。由于数据集的大小(1万对值),我需要将其保存为外部文件类型。
原因是如何编译我的数据。要保存某人手动将数据输入数组,该项目将基于Excel,保存为CSV,使用临时Java程序解析为文件格式(例如jJSON),该文件格式可以添加到我的项目资源文件夹中。然后,我可以从此集中检索数据,而我的应用程序不必在创建应用程序时手动将巨大的数组加载到内存中。我可以很容易地在运行时解析CSV以“填充”一个数组(或类似数组)-但是我担心在移动设备上,内存开销会很大吗?
我已经审查了Suitable Java data structure for parsing large data file和Data structure options for efficiently storing sets of integer pairs on disk?的答案,但无法得出明确的结论。
我曾尝试保存到.JSON文件,但是不确定是否可以请求随机输入,而且对于保存简单结构而言,这似乎很麻烦。是treeMap或哈希表,我需要集中精力进行搜索。
为了给查询提供一些上下文,我的应用程序将在android上运行,并且需要引用一个定义(大约500个字符的String)和一个转换因子(一个Float)。我需要检索随机数据条目。用户在会话期间只能发出2或3个请求-因此,将10k元素数组加载到内存中毫无意义。查询:Android手机上潜在的现代技术很容易解决这种查询问题,如果我在运行时解析数百万个条目,这也许只是个问题?
如果可以提供所需的功能,我愿意使用SQLlite来保存我的数据。请注意,数据集必须来自excel易于导出的文件格式(CSV,TXT等)。
您能给我的任何建议将不胜感激。
最佳答案
这是一种可能的设计,在提供快速访问的同时需要最小的内存占用:
从以逗号分隔或制表符分隔的值的数据文件开始,以便在数据对之间使用换行符。
保留一个long
值数组,该值与数据文件中各行的索引相对应。当知道行的位置时,可以使用InputStream.skip()
前进到所需的行。这利用了以下事实:对于skip()
,read
通常比InputStream
快很多。
您将具有一些在初始化时运行的设置代码以对行进行索引。
增强功能是仅对第n行进行索引,以使数组更小。因此,如果n为100,而您正在访问第1003行,则使用第10个索引跳到第1000行,然后再读取另外两行以到达第1003行。这使您可以调整数组的大小以使用较少的内存。
我认为这是一个有趣的问题,所以我整理了一些代码来测试我的想法。它使用一个示例4MB CSV文件,该文件是我从一些大数据网站上下载的,该网站包含约36,000行数据。大多数行的长度超过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
,因此我可以输入行号。因此,为了让您对性能有所了解,第一阶段平均需要1600毫秒才能读取整个文件。我使用的
MULTIPLE
值为10。访问文件中的最后一条记录平均需要30毫秒。我认为,仅占用29312字节的内存就可以将访问时间降低到30ms,这是相当不错的。
您可以see the sample project on GitHub。