我想做的是将行重新排列(从CSV读取),然后将第一个随机化的10,000行打印到一个csv,将剩余的行打印到单独的csv。使用较小的文件,我可以执行类似
的操作java.util.Collections.shuffle(...)
for (int i=0; i < 10000; i++) printcsv(...)
for (int i=10000; i < data.length; i++) printcsv(...)
然而,对于非常大的文件,我现在得到OutOfMemoryError
答案 0 :(得分:3)
你可以:
使用更多内存或
不是实际的CSV行,而是只有一组行号,然后逐行读取输入文件(当然是缓冲的)并将该行写入所需的输出文件之一。
答案 1 :(得分:2)
你可以记忆地映射文件并查找所有换行符,存储在int
或long
的数组中。创建一个int
索引数组,然后对其进行随机播放。这应该每行使用大约8-32个字节。如果这不适合内存,您也可以为这些数组使用内存映射文件。
答案 2 :(得分:1)
使用某种索引方案。解析一次CSV文件以获取行数(不要在内存中保留任何内容,只需解析它)并随机选择该范围内的10,000个数字(确保避免重复,例如使用Set<Integer>
或更复杂的东西)。然后再次解析CSV,再次维护行的计数器。如果行号对应于您随机选择的某个数字,请将其输出到一个CSV文件。将具有不匹配数字的行输出到另一个文件。
答案 3 :(得分:1)
N
。1
的{li> Take a random sample大小为10,000 N
。
file1
;否则,请将其写入file2
。使用reservoir sampling 执行步骤1时,可以完成步骤2。
答案 4 :(得分:1)
这是一种可能的算法:
答案 5 :(得分:0)
如果您知道文件中的行数以及是否将完整行随机化,则可以按行号随机化,然后读取所选行。只需通过Random类选择一个随机行并存储随机数列表,这样就不会选择一个。
BufferedReader reader = new BufferedReader(new FileReader(new File("file.cvs")));
BufferedWriter chosen = new BufferedWriter(new FileWriter(new File("chosen.cvs")));
BufferedWriter notChosen = new BufferedWriter(new FileWriter(new File("notChosen.cvs")));
int numChosenRows = 10000;
long numLines = 1000000000;
Set<Long> chosenRows = new HashSet<Long>(numChosenRows+1, 1);
for(int i = 0; i < numChosenRows; i++) {
while(!chosenRows.add(nextLong(numLines))) {
// add returns false if the value already exists in the Set
}
}
String line;
for(long lineNo = 0; (line = reader.readLine()) != null; lineNo++){
if(chosenRows.contains(lineNo)){
// Do nothing for the moment
} else {
notChosen.write(line);
}
}
// Randomise the set of chosen rows
// Use RandomAccessFile to write the rows in that order
请参阅this answer了解nextLong方法,该方法生成一个随机长度缩放到特定大小。
编辑:与大多数人一样,我忽略了以随机顺序编写随机选择的行的要求。我假设RandomAccessFile会对此有所帮助。只需使用所选行随机化List,然后按顺序访问它们。对于未选择的那些,我编辑了上面的代码,简单地忽略了所选择的代码。