如何在Java中获得一个文本文件的随机行?

说有一个文件太大,不能记忆。 我怎样才能从它的随机线? 谢谢。

更新:我想要得到每一行的概率是平等的。

这是一个解决scheme。 看看真正的东西(main()方法反复练习choose()的choose()方法,以显示分布确实相当一致)。

这个想法很简单:当你阅读第一行时,有100%的机会被选中。 当你读第二行时,有50%的机会replace第一行。 当你阅读第三行时,有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; } } 

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

  1. 使用RandomAccessFile在文件中寻找一个随机的字节位置。
  2. 寻找左边和右边的下一行结束符。 让他们之间的界线。
  3. 以概率(MIN_LINE_LENGTH / L.length)返回L.否则,从第1步开始。

这是拒绝抽样的一个变种。

行长度包括行结束符字符,因此MIN_LINE_LENGTH> = 1(如果知道行长度更紧的话,所有这一切都会更好)。

值得注意的是,这个algorithm的运行时间并不取决于文件的大小,而仅仅取决于行的长度,即它比读整个文件要好得多。

或者你

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

  2. 使用油藏采样

查看Itay的答案,看起来好像是在取一行代码后读取文件一千遍以上,而真正的油藏采样只应该超过“磁带”一次。 我已经devise了一些代码,在真实的油藏采样过程中进行一次编码,基于这个和networking上的各种描述。

 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的机会。 我希望这提供更有效的代码。 请让我知道,如果这不适合你,因为我在半个小时之内就把它打翻了。

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