2009-06-30 7 views

Répondre

37

La solution la plus simple est tout simplement naïf:

$file = "/path/to/file"; 
$data = file($file); 
$line = $data[count($data)-1]; 

Bien, cela charger le fichier en mémoire. Peut-être un problème (ou pas). Une meilleure solution est la suivante:

$file = escapeshellarg($file); // for the security concious (should be everyone!) 
$line = `tail -n 1 $file`; 
+0

place sur, merci Matthew – waxical

+0

FYI, j'ai utilisé la queue ... – waxical

+1

Notez que c'est très dangereux sauf si vous utilisez escapeshellarg(): http://de.php.net/manual/fr/function.escapeshellarg.php – soulmerge

2

Vous devez soit lire le fichier ligne par ligne et enregistrer la dernière ligne de lecture pour l'obtenir.

Ou si sur unix/linux vous pouvez envisager d'utiliser la commande shell queue

tail -n 1 filename 
13

Cela ressemble à c'est ce que vous cherchez:

tekkie.flashbit.net: Tail functionality in PHP

Il met en oeuvre une fonction utilise fseek() avec un index négatif pour remonter le fichier depuis la fin. Vous pouvez définir le nombre de lignes que vous souhaitez renvoyer.

Le code est également disponible as a Gist on GitHub:

// full path to text file 
define("TEXT_FILE", "/home/www/default-error.log"); 
// number of lines to read from the end of file 
define("LINES_COUNT", 10); 


function read_file($file, $lines) { 
    //global $fsize; 
    $handle = fopen($file, "r"); 
    $linecounter = $lines; 
    $pos = -2; 
    $beginning = false; 
    $text = array(); 
    while ($linecounter > 0) { 
     $t = " "; 
     while ($t != "\n") { 
      if(fseek($handle, $pos, SEEK_END) == -1) { 
       $beginning = true; 
       break; 
      } 
      $t = fgetc($handle); 
      $pos --; 
     } 
     $linecounter --; 
     if ($beginning) { 
      rewind($handle); 
     } 
     $text[$lines-$linecounter-1] = fgets($handle); 
     if ($beginning) break; 
    } 
    fclose ($handle); 
    return array_reverse($text); 
} 

$fsize = round(filesize(TEXT_FILE)/1024/1024,2); 

echo "<strong>".TEXT_FILE."</strong>\n\n"; 
echo "File size is {$fsize} megabytes\n\n"; 
echo "Last ".LINES_COUNT." lines of the file:\n\n"; 

$lines = read_file(TEXT_FILE, LINES_COUNT); 
foreach ($lines as $line) { 
    echo $line; 
} 
+0

Ii intéressant ... mais tout à fait inutile à côté de la méthode beaucoup plus facile de bombarder le problème (sauf si vous êtes vraiment sur un serveur très sérieusement surmené) –

+6

"totalement inutile" est un peu dur – Tomalak

+0

Ok, peut-être un peu ... encore, je ne serais pas enclin à l'utiliser, à moins que quelqu'un puisse me prouver que l'utilisation de 'tail' était en fait ce qui causait des goulots d'étranglement et non les opérations sur de grandes bases de données. –

0

Si vous voulez lire un fichier ligne par ligne la fonction file lit le contenu d'un fichier, ligne par ligne et retourne chaque ligne comme un élément d'un tableau.

Vous pourriez faire quelque chose de simple comme:

$lines = file('log.txt'); 
$lastLine = array_pop($lines); 
+3

Vraiment? Pour un fichier journal de plusieurs mégaoctets dont 99,99% ne m'intéresse pas, j'essayerais d'éviter de tout charger dans un tableau pour le jeter immédiatement. – Tomalak

+0

Ne pas nier que c'est inefficace, mais cela fonctionne; et qui sait combien de temps le fichier est? J'utiliserais la commande tail dans mon environnement, mais WiseDonkey n'en a pas spécifié. C'est une bonne fonction que vous avez liée, cependant. –

+1

file() et file_get_contents() sont toutes les deux de grandes fonctions de manipulation de fichiers, surtout si vous savez que les fichiers impliqués sont relativement petits et veulent juste faire quelque chose rapidement et facilement. –

7
define('YOUR_EOL', "\n"); 
$fp = fopen('yourfile.txt', 'r'); 

$pos = -1; $line = ''; $c = ''; 
do { 
    $line = $c . $line; 
    fseek($fp, $pos--, SEEK_END); 
    $c = fgetc($fp); 
} while ($c != YOUR_EOL); 

echo $line; 

fclose($fp); 

Cela vaut mieux, car il ne charge pas le fichier complet en mémoire ...

Set YOUR_EOL à vos fins de ligne correcte, si vous utilisez le même les fins de ligne en tant que terminaisons de ligne par défaut du système d'exploitation sur lequel réside votre script, vous pouvez utiliser la constante PHP_EOL.

1

Celui-ci ne cassera pas pour un fichier de ligne 1 ou 0.

function readlastline($fileName) 
{ 

     $fp = @fopen($fileName, "r"); 
     $begining = fseek($fp, 0);  
     $pos = -1; 
     $t = " "; 
     while ($t != "\n") { 
      fseek($fp, $pos, SEEK_END); 
      if(ftell($fp) == $begining){ 
       break; 
      } 
      $t = fgetc($fp); 
      $pos = $pos - 1; 
     } 
     $t = fgets($fp); 
     fclose($fp); 
     return $t; 
} 
4
function seekLastLine($f) { 
    $pos = -2; 
    do { 
     fseek($f, $pos--, SEEK_END); 
     $ch = fgetc($f); 
    } while ($ch != "\n"); 
} 

-2 parce que le dernier caractère peut être \n

1

... Pourquoi viens de lire la dernière ligne?

function readLines($fp, $num) { 

    $line_count = 0; $line = ''; $pos = -1; $lines = array(); $c = ''; 

    while($line_count < $num) { 
     $line = $c . $line; 
     fseek($fp, $pos--, SEEK_END); 
     $c = fgetc($fp); 
     if($c == "\n") { $line_count++; $lines[] = $line; $line = ''; $c = ''; } 
    } 
    return $lines; 
} 

$filename = "content.txt"; 
$fp = @fopen($filename, "r"); 

print_r(readLines($fp, 2)); 

fclose($fp); 
+2

Parce que c'est ce dont le PO avait besoin? lol – dtbarne

0

@unique_stephen, votre réponse est erronée. PHP fseek renvoie 0 pour le succès et -1 pour l'échec. Stocker le résultat dans $ begin (sic) et ensuite l'utiliser dans un filtre pour ftell() n'est pas correct. Si ma réputation était plus élevée, je vous aurais voté et laissé un commentaire. Voici une version modifiée de la fonction unique_stephen.

function readlastline($fileName) 
{ 
    $fp = @fopen($fileName, "r"); 
    if (fseek($fp, 0) == -1) 
     exit('Cannot seek to beginning of the file'); 
    $pos = -1; 
    $t = " "; 
    while ($t != "\n") { 
     if (fseek($fp, $pos, SEEK_END) == -1) 
      exit('Cannot seek to the end of the file'); 
     if (ftell($fp) == 0) { 
      break; 
     } 
     $t = fgetc($fp); 
     $pos = $pos - 1; 
    } 
    $t = fgets($fp); 
    fclose($fp); 
    return $t; 
} 

REMARQUE: le fseek de PHP ne parvient pas à chercher à la fin des fichiers de plus de PHP_MAX_INT qui est signé 32bit même sur les binaires 64 bits.

+1

Ceci ne fournit pas de réponse à la question. Une fois que vous avez suffisamment [réputation] (https://stackoverflow.com/help/whats-reputation) vous pourrez [commenter n'importe quel article] (https://stackoverflow.com/help/privileges/comment); Au lieu de cela, [fournissez des réponses qui ne nécessitent pas de précisions de la part du demandeur] (https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can- je-fais-à la place). - [À revoir] (/ review/low-quality-posts/18923154) –

+0

Oui, il y a déjà des réponses à la question.Le problème de ne pas pouvoir laisser un commentaire sur une réponse est ce qui doit être résolu si vous ne voulez pas que je laisse une réponse en commentaire. Je vais modifier la réponse pour donner une version correcte de la réponse @ unique_stephen. – Earnie

Questions connexes