如何在Java中获取文本文件的随机行?

时间:2010-02-07 19:35:58

标签: java

假设有一个文件太大而无法存入内存。如何从中获取随机线?感谢。

更新: 我想要让每一条线相等的概率。

7 个答案:

答案 0 :(得分:23)

如果只想要一行,则读取整个文件似乎有点过分。以下应该更有效:

  1. 使用RandomAccessFile寻找文件中的随机字节位置。
  2. 向左和向右寻找下一行终止符。让他们之间的界限。
  3. 以概率(MIN_LINE_LENGTH / L.length)返回L.否则,请从步骤1开始。
  4. 这是rejection sampling的变体。

    行长度包括行终止符(s),因此MIN_LINE_LENGTH> = 1.(如果您知道行长度更紧密,那就更好了。)

    值得注意的是,此算法的运行时间不依赖于文件大小,仅取决于行长度,即它比读取整个文件要好得多。

答案 1 :(得分:19)

这是一个解决方案。看一下执行真实事物的choose()方法(main()方法反复练习choose(),以显示分布确实非常均匀)。

这个想法很简单:当你阅读第一行时,它有100%的机会被选为结果。当您阅读第2行时,它有50%的机会替换第一行作为结果。当你阅读第3行时,它有33%的机会成为结果。第四行有25%,依旧......

import java.io.*;
import java.util.*;

public class B {

  public static void main(String[] args) throws FileNotFoundException {
     Map<String,Integer> map = new HashMap<String,Integer>();
     for(int i = 0; i < 1000; ++i)
     {
        String s = choose(new File("g:/temp/a.txt"));
        if(!map.containsKey(s))
           map.put(s, 0);
        map.put(s, map.get(s) + 1);
     }

     System.out.println(map);
  }

  public static String choose(File f) throws FileNotFoundException
  {
     String result = null;
     Random rand = new Random();
     int n = 0;
     for(Scanner sc = new Scanner(f); sc.hasNext(); )
     {
        ++n;
        String line = sc.nextLine();
        if(rand.nextInt(n) == 0)
           result = line;         
     }

     return result;      
  }
}

答案 2 :(得分:9)

你要么

  1. 读取文件两次 - 一次计算行数,第二次提取随机行,或

  2. 使用reservoir sampling

答案 3 :(得分:6)

查看Itay的答案,看起来它在采样一行代码后读取文件一千次,而真正的水库采样应该只过了一次“磁带”。我已经设计了一些代码,根据this以及网络上的各种描述,通过真实的水库采样来验证代码。

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;

public class reservoirSampling {

    public static void main(String[] args) throws FileNotFoundException, IOException{
        Sampler mySampler = new Sampler();
        List<String> myList = mySampler.sampler(10);
        for(int index = 0;index<myList.size();index++){
            System.out.println(myList.get(index));
        }
    }
}

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;

public class Sampler {

    public Sampler(){}
    public List<String> sampler (int reservoirSize) throws FileNotFoundException, IOException
    {
        String currentLine=null;
        //reservoirList is where our selected lines stored
        List <String> reservoirList= new ArrayList<String>(reservoirSize); 
        // we will use this counter to count the current line number while iterating
        int count=0; 

        Random ra = new Random();
        int randomNumber = 0;
        Scanner sc = new Scanner(new File("Open_source.html")).useDelimiter("\n");
        while (sc.hasNext())
        {
            currentLine = sc.next();
            count ++;
            if (count<=reservoirSize)
            {
                reservoirList.add(currentLine);
            }
            else if ((randomNumber = (int) ra.nextInt(count))<reservoirSize)
            {
                reservoirList.set(randomNumber, currentLine);
            }
        }
        return reservoirList;
    }
}

基本前提是你填满水库,然后回到它并填充1 / ReservoirSize机会的随机线。我希望这能提供更高效的代码。如果这对你不起作用,请告诉我,因为我已经在半小时内把它搞砸了。

答案 4 :(得分:1)

在java中从文件中随机读取一行:

public String getRandomLineFromTheFile(String filePathWithFileName) 抛出异常 {

    File file = new File(filePathWithFileName); 
    final RandomAccessFile f = new RandomAccessFile(file, "r");
    final long randomLocation = (long) (Math.random() * f.length());
    f.seek(randomLocation);
    f.readLine();
    String randomLine = f.readLine();
    f.close();
    return randomLine;
}

答案 5 :(得分:0)

使用 RandomAccessFile

  1. 构造一个 RandomAccessFile 文件
  2. 通过调用 file.length()
  3. 来获取该文件的长度 filelen
  4. 生成一个介于0和 filelen
  5. 之间的随机数 pos
  6. 致电 file.seek(pos) 以寻找随机位置
  7. 调用 file.readLine() 到达当前行的末尾
  8. 再次调用 file.readLine() 来读取下一行

使用这种方法,我一直在从布朗语料库中随机采样行,并且可以在几秒钟内轻松地从随机选择的文件中检索1000个随机样本。如果我尝试逐行阅读每个文件来做同样的事情,那将花费我更长的时间。

可以使用相同的原理从列表中选择随机元素。如果您生成一个介于0和列表长度之间的随机数,则无需阅读列表并停在一个随机的位置,而是可以直接索引到列表中。

答案 6 :(得分:-1)

使用BufferedReader并逐行读取。使用java.util.Random对象随机停止;)