行が単なるテキストで長さが可変の場合、どの行が #97 であるかを知ることはできません。97 番目になるのは、前に 96 行あることだけです。
そのため、その時点までのファイル全体を読み取る必要があります (これが SplFileObject の機能です)。
$fp = fopen("keywords.txt", "r");
while($line--)
{
if (feof($fp))
// ERROR: line does not exist
$text = fgets($fp, 1024); // 1024 = max length of one line
}
fclose($fp);
しかし、各行の前に行番号を保存できる場合、つまりファイルは
...
95 abbagnale
96 abbatangelo
97 abbatantuono
98 ...
次に、一種の二分探索を実装できます。
- start with s1 = 0 and s2 = file length
- read a keyword and line number at seek position s3 = (s1+s2)/2 (*)
- if line number is less than desired, s1 = s3; else s2 = s3; and repeat previous step.
- if line number is the one desired, strip the number from the text and you get the keyword.
(*) 行は正確に s# で開始されない可能性が高いため、 2 つのfgetsが必要です。「近い」場合は、より大きなチャンクを読み取って行に分割する方が高速になります。たとえば、170135 行をシークして 170180 行を読み込むとします。シーク位置を 1 キロバイト巻き戻し、1 キロバイトのデータを読み込み、そこで 170135 をシークします。
または、さまざまな行の長さがあまり変わらない場合は、固定サイズの行を保存する価値があります (ここで、「#」は実際にはスペースである必要があり、行の長さでは、行末記号をカウントする必要があります \nまたは \r\n):
abbagnale#########
abbatangelo#######
abbatantuono######
次に、各キーワードが 32 バイトであるとします。
$fp = fopen("keywords.txt", "r");
fseek($fp, 97 * 32, SEEK_SET);
$text = trim(fgets($fp, 32));
fclose($fp);
多かれ少なかれ瞬時になります。
ただし、ファイルがリモート サーバー上にある場合でも、ファイル全体 (目的の行まで) をダウンロードする必要があります。検索を実行できるリモート サーバー上に「スキャナー」スクリプトを配置することで、より適切なサービスを提供できます。その後、実行できます
$text = file_get_contents("http://www.mysite.com/keywords.php?line=97");
ミリ秒単位でラインを取得します。