5

3000 万のユーザー ID を持つ大きなファイルがあります。その大きなファイルは次のようになり、各行にはユーザー ID が含まれます。

149905320
1165665384
66969324
886633368
1145241312
286585320
1008665352
1135545396
186217320
132577356

今、私はその大きなテキスト ファイルからランダムな行を取得することを計画しています。その大きなテキスト ファイルに含まれるユーザー ID の総数を知っています。その大きなテキスト ファイルからランダムな要素を選択する最良の方法が何であるかはわかりません。これらの 3000 万のユーザー ID をすべてセットに格納し、hastset から要素をランダムに選択することを考えていましたが、このアプローチではメモリ不足エラーが発生します。

そのため、大きなテキスト ファイルから要素をランダムに選択しようとしています。

final String id = generateRandomUserId(random);

/**
 * Select random elements from the a big text file
 * 
 * @param userIdsSet2
 * @param r
 * @return
 */
private String generateRandomUserId(Random r) {

     File bigFile = new File("C:\\bigfile.txt");

     //randomly select elements from a big text file         


}

これを行う最良の方法は何ですか?

4

3 に答える 3

7

あなたはそうすることができます:

  • ファイルのサイズを取得します (バイト単位)
  • バイトを選択します ([0..file.length()] でランダムに選択された数値 - RandomAccessFile)
  • ファイル内のその位置にシークする ( file.seek(number))
  • \n次の文字の直後にシークする( file.seek(1))
  • 行を読む ( file.readLine())

例えば...

この方法では、何も保存する必要はありません。

サンプルの理論的なスニペットは次のようになります (いくつかの副作用が含まれています)。

File f = new File("D:/abc.txt");
RandomAccessFile file;
try {
    file = new RandomAccessFile(f, "r");
    long file_size = file.length();
    long chosen_byte = (long)(Math.random() * file_size);

    file.seek(chosen_byte);

    for (;;)
    {
        byte a_byte = file.readByte();
        char wordChar = (char)a_byte;
        if (chosen_byte >= file_size || wordChar == '\n' || wordChar == '\r' || wordChar == -1) break;
        else chosen_byte += 1;
        System.out.println("\"" + Character.toString(wordChar)  + "\"");
    }

    int chosen = -1;
    if (chosen_byte < file_size) 
    {
        String s = file.readLine();
        chosen = Integer.parseInt(s);
        System.out.println("Chosen id : \"" + s  + "\"");
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}


編集: 完全に機能する(理論的には)クラス

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;


public class Main {

    /**
     * WARNING : This piece of code requires that the input file terminates by a BLANK line !
     * 
     * @param args
     * @throws Exception 
     */
    public static void main(String[] args) throws Exception {

        File f = new File("D:/abc.txt");
        RandomAccessFile file;

        try {

            file = new RandomAccessFile(f, "r");
            long file_size = file.length();

            // Let's start
            long chosen_byte = (long)(Math.random() * (file_size - 1));
            long cur_byte = chosen_byte;

            // Goto starting position
            file.seek(cur_byte);

            String s_LR = "";
            char a_char;

            // Get left hand chars
            for (;;)
            {
                a_char = (char)file.readByte();
                if (cur_byte < 0 || a_char == '\n' || a_char == '\r' || a_char == -1) break;
                else 
                {
                    s_LR = a_char + s_LR;
                    --cur_byte;
                    if (cur_byte >= 0) file.seek(cur_byte);
                    else break;
                }
            }

            // Get right hand chars
            cur_byte = chosen_byte + 1;
            file.seek(cur_byte);
            for (;;)
            {
                a_char = (char)file.readByte();
                if (cur_byte >= file_size || a_char == '\n' || a_char == '\r' || a_char == -1) break;
                else 
                {
                    s_LR += a_char;
                    ++cur_byte;
                }
            }

            // Parse ID
            if (cur_byte < file_size) 
            {
                int chosen_id = Integer.parseInt(s_LR);
                System.out.println("Chosen id : " + chosen_id);
            }
            else
            {
                throw new Exception("Ran out of bounds. But this usually never happen...");
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}


これが実装として間違っていないことを願っています(私は当時よりC++です)...

于 2013-06-20T00:20:54.340 に答える
0

OPには、「その大きなテキストファイルに含まれるユーザーIDの総数を知っています」と記載されています。これをNとします。

  • 1 から N までの乱数を生成します。
  • N 番目の行に到達するまで、行を読み取ります (BufferedReader)。
  • 終わり
于 2013-06-20T03:57:11.400 に答える