在Java中,有没有办法随机化一个太大的文件以适应内存?

时间:2011-10-24 12:15:08

标签: java out-of-memory

我想做的是将行重新排列(从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

6 个答案:

答案 0 :(得分:3)

你可以:

  • 使用更多内存或

  • 不是实际的CSV行,而是只有一组行号,然后逐行读取输入文件(当然是缓冲的)并将该行写入所需的输出文件之一。

答案 1 :(得分:2)

你可以记忆地映射文件并查找所有换行符,存储在intlong的数组中。创建一个int索引数组,然后对其进行随机播放。这应该每行使用大约8-32个字节。如果这不适合内存,您也可以为这些数组使用内存映射文件。

答案 2 :(得分:1)

使用某种索引方案。解析一次CSV文件以获取行数(不要在内存中保留任何内容,只需解析它)并随机选择该范围内的10,000个数字(确保避免重复,例如使用Set<Integer>或更复杂的东西)。然后再次解析CSV,再次维护行的计数器。如果行号对应于您随机选择的某个数字,请将其输出到一个CSV文件。将具有不匹配数字的行输出到另一个文件。

答案 3 :(得分:1)

  1. 首先,通过读取输入文件的内容(但不将其存储在内存中)来计算输入文件中的行数。拨打行数N
  2. 数量为1的{​​li> Take a random sample大小为10,000 N
  3. 从头开始阅读输入文件。对于每一行,如果行号在步骤2中绘制的样本中,则将行写入file1;否则,请将其写入file2
  4. 使用reservoir sampling 执行步骤1时,可以完成步骤2。

答案 4 :(得分:1)

这是一种可能的算法:

  1. 设MAX_LINES为可管理文件中的最大行数;
  2. 从输入文件中读取MAX_LINES,使用原始算法将它们随机化并将它们写入临时文件;
  3. 重复2.直到输入文件中没有剩余行;
  4. 设N是0和你写的临时文件数之间的随机数;从第N个临时文件中读取下一行;
  5. 重复4.直到你读完所有文件中的所有行;前10000次将每一行写入第一个输出文件,将所有其他行写入另一个文件。

答案 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,然后按顺序访问它们。对于未选择的那些,我编辑了上面的代码,简单地忽略了所选择的代码。