我对PHP很满意,但可能没有这里的一些人好一半。
我基本上是想找到一种方法,从一个巨大的文本文件中抓取一行。。。。它基本上是一个我想通过电话号码拨打的关键词列表,但最好不要在我到达那一行之前把它们全部看完。。。。。否则显然会影响我的服务器。
目前我正在使用这个
$lines = file('http://www.mysite.com/keywords.txt');
foreach ($lines as $line_num => $line) {
echo "$line_num";
}
这是有效的,但我确信必须有一种更好的方法来节省使用,因为这是将整个文件放入内存中,如果我可以简单地对php说,给我97行,嗯,规则。。。。
希望你们能想出一个比我聪明得多的解决方案:p ty
使用SplFileObject
$file = "test.txt";
$line_number = 1000;
$file_obj = new SplFileObject( $file );
/*** seek to the line number ***/
$file_obj->seek( $line_number );
/*** return the current line ***/
echo $file_obj->current();
如果行只是文本并且长度可变,则无法知道哪一行是#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#开始,因此您需要两个fgets:一个用于消除虚假的half关键字,另一个用于读取行号。当你"接近"时,读取更大的块并将其拆分成行会更快。例如,您搜索第170135行,然后在第170180行中读取:您最好将搜索位置倒退1千字节,读取1千字节的数据,然后在其中搜索170135。
或者,如果不同行的长度相差不大,那么存储一条固定大小的行可能是值得的(这里的"#"实际上应该是空格,并且在行长度中您需要计算行终止符,''r''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);
将或多或少是瞬时的。
不过,如果文件在远程服务器上,您仍然需要下载整个文件(直到所需的行),最好在可以运行搜索的远程服务器上放置一个"scanner"脚本。然后你可以运行
$text = file_get_contents("http://www.mysite.com/keywords.php?line=97");
并在几毫秒内得到你的线路。
几乎任何语言都无法从文件中获取"行号x",而无需先以某种方式读取。毕竟,一行只是两个行尾字符之间的东西。从文件中提取"字符号x"可以在不加载整个文件的情况下完成(有一些困难),而提取"行号x"则不能在不加载x之前的所有行的情况下进行(在大多数方法中,您需要加载所有行)
加载所有行直到行x的方法如下(使用fgets):
$f = fopen('http://www.mysite.com/keywords.txt');
$i=97
$text=""
while (($text = fgets($f,2048)) !== false && $i>0) {
$i--
}
echo $text