PHP:从文件中读取特定行

69

我正在尝试使用PHP从文本文件中读取特定行。

这是文本文件内容:

foo  
foo2

如何使用php获取第二行的内容?以下代码仅返回第一行:

<?php 
$myFile = "4-24-11.txt";
$fh = fopen($myFile, 'r');
$theData = fgets($fh);
fclose($fh);
echo $theData;
?>

但我需要第二个。

任何帮助都将不胜感激。

13个回答

100

85
如果文件大小很大,这个解决方案会变得缓慢并占用大量内存。 - Raptor
23
为了获取第二行文本而将整个文件读入内存,在某些情况下可能会导致灾难性后果(参见Raptor的评论)。 - Tomm
在处理较大的文件时,请使用Alex的解决方案。 - Hafenkranich
从技术上讲是正确的,但并不是最优解,特别是当你处理可能有数百万行的文件时。 - GordonM

46

omg我还差7个声望才能评论。这是@Raptor和@Tomm的评论,因为这个问题在谷歌搜索结果中仍然排名很高。

他完全正确。对于小文件,file($file);非常好用。但对于大文件来说,它太过浪费资源了,因为PHP数组会消耗大量内存。

我刚刚进行了一个小测试,使用大小约为67MB(1,000,000行)的*.csv文件:

$t = -microtime(1);
$file = '../data/1000k.csv';
$lines = file($file);
echo $lines[999999]
    ."\n".(memory_get_peak_usage(1)/1024/1024)
    ."\n".($t+microtime(1));
//227.5
//0.22701287269592
//Process finished with exit code 0

既然还没有人提到它,我尝试了一下 SplFileObject,实际上这是我最近才发现的。

$t = -microtime(1);
$file = '../data/1000k.csv';
$spl = new SplFileObject($file);
$spl->seek(999999);
echo $spl->current()
    ."\n".(memory_get_peak_usage(1)/1024/1024)
    ."\n".($t+microtime(1));
//0.5
//0.11500692367554
//Process finished with exit code 0

这是在我的Win7桌面上,所以不代表生产环境,但仍然...相差甚远。


4
请注意,SplFileObject会锁定文件。因此,当不再需要该类时,请将其设置为null(例如 $spl = null;),否则您将被拒绝对该文件执行其他操作 - 如删除、重命名、在类之外访问等。 - Wh1T3h4Ck5

21

如果你想以那种方式去做...

$line = 0;

while (($buffer = fgets($fh)) !== FALSE) {
   if ($line == 1) {
       // This is the second line.
       break;
   }   
   $line++;
}

或者使用file()打开文件,并使用下标[1]访问行。


所以基本上,将它输入到一个数组中并提取第二个条目。我明白了。谢谢。 - Sang Froid
@Sang 第一个解决方案是根据你现在的代码给出的。 - alex

20

我会使用 SplFileObject 类...

$file = new SplFileObject("filename");
if (!$file->eof()) {
     $file->seek($lineNumber);
     $contents = $file->current(); // $contents would hold the data from line x
}

8
你可以使用以下方法获取文件中的所有行:
$handle = @fopen('test.txt', "r");

if ($handle) { 
   while (!feof($handle)) { 
       $lines[] = fgets($handle, 4096); 
   } 
   fclose($handle); 
} 


print_r($lines);

第二行使用$lines[1]

相关的IT技术内容。


6
$myFile = "4-21-11.txt";
$fh = fopen($myFile, 'r');
while(!feof($fh))
{
    $data[] = fgets($fh);  
    //Do whatever you want with the data in here
    //This feeds the file into an array line by line
}
fclose($fh);

4
顺便说一下,如果您可能会使用任何大文件,将整个文件输入数组中,例如使用file()file_get_contents(),在实践中是不建议的。对于小文件,这很好用。 - Phoenix

5

这个问题现在已经很老了,但是对于处理非常大的文件的人来说,这里有一个解决方案,它不需要读取每一行之前的内容。这也是我在处理大约1.6亿行的文件时唯一有效的解决方案。

<?php
function rand_line($fileName) {
    do{
        $fileSize=filesize($fileName);
        $fp = fopen($fileName, 'r');
        fseek($fp, rand(0, $fileSize));
        $data = fread($fp, 4096);  // assumes lines are < 4096 characters
        fclose($fp);
        $a = explode("\n",$data);
    }while(count($a)<2);
    return $a[1];
}

echo rand_line("file.txt");  // change file name
?>

它的工作原理是打开文件但不读取任何内容,然后立即将指针移动到随机位置,从那个位置读取最多4096个字符,然后从这些数据中获取第一行完整的内容。


考虑速度,您对于完全匹配整行内容的解决方案是什么? - Artis Zel
根据数据是静态还是未知的,选择不同的方法。对于静态数据,哈希表查找是最快的。对于未知/随机数据,我认为通过线程处理的顺序或并行顺序将是最快的。 - cantelope

3
如果您在Linux上使用PHP,可以尝试以下方法读取例如第74至159行之间的文本:
$text = shell_exec("sed -n '74,159p' path/to/file.log");

如果您的文件比较大,这种解决方案就很不错。


1
虽然这个解决方案在你知道它将要部署的位置时是有效的,但对于你不知道目标系统的情况来说并不是最优的。 - Tarulia

2
你需要循环文件直到文件结尾。
  while(!feof($file))
  {
     echo fgets($file). "<br />";
  }
  fclose($file);

1

我喜欢 daggett answer,但如果你的文件不够大,还有另一种解决方案可以尝试。

$file = __FILE__; // Let's take the current file just as an example.

$start_line = __LINE__ -1; // The same with the line what we look for. Take the line number where $line variable is declared as the start.

$lines_to_display = 5; // The number of lines to display. Displays only the $start_line if set to 1. If $lines_to_display argument is omitted displays all lines starting from the $start_line.

echo implode('', array_slice(file($file), $start_line, lines_to_display));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接