2009-06-30 13 views

Respuesta

37

La solución más sencilla es simplemente ingenua:

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

Sin embargo, esto va a cargar todo el archivo en la memoria. Posiblemente un problema (o no). Una mejor solución es la siguiente:

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

mancha, gracias Matthew – waxical

+0

FYI, usé cola ... – waxical

+1

Tenga en cuenta que esto es muy inseguro a menos que esté usando escapeshellarg(): http://de.php.net/manual/en/function.escapeshellarg.php – soulmerge

2

O tiene que leer el archivo en línea por línea y guardar la última línea de lectura para obtenerlo.

O si en UNIX/Linux es posible considerar el uso de la cola de comandos shell

tail -n 1 filename 
13

Esto parece que es lo que busca:

tekkie.flashbit.net: Tail functionality in PHP

Implementa una función que usa fseek() con un índice negativo para enrollar el archivo desde el final. Puede definir cuántas líneas desea devolver.

El código también está 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

I interesante ... pero totalmente inútil junto al método mucho más sencillo de descascarar el problema hasta la cola (a menos que realmente estés en un servidor muy sobrecargado) –

+6

"completamente inútil" es un poco duro – Tomalak

+0

Ok, tal vez un poco ... aún así, no estaría dispuesto a usarlo, a menos que alguien pudiera probarme que el uso de 'tail' era realmente lo que estaba causando cuellos de botella y no las operaciones en bases de datos grandes. –

0

Si desea leer un archivo línea por línea de la función file lee el contenido de un archivo, línea por línea y devuelve cada línea como un elemento de una formación.

Así se podría hacer algo tan simple como:

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

¿De verdad? Para un archivo de registro de varios megabytes del cual el 99.99% no me interesa, trataré de evitar cargarlo todo en una matriz solo para desecharlo inmediatamente. – Tomalak

+0

Sin negar que esto es ineficiente, pero funciona; y quién sabe por cuánto tiempo está el archivo? Utilizaría el comando tail en mi entorno, pero WiseDonkey no especificó ninguno. Sin embargo, esa es una función agradable con la que te vinculaste. –

+1

file() y file_get_contents() son funciones geniales de manipulación de archivos, especialmente si usted sabe que los archivos involucrados son relativamente pequeños y solo desea hacer algo rápida y fácilmente. –

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); 

Esto es mejor, ya que no carga el archivo completo en la memoria ...

Conjunto YOUR_EOL a sus finales de línea correctos, si se utiliza la misma finales de línea como terminaciones de línea por defecto del sistema operativo donde reside su secuencia de comandos, puede usar la constante PHP_EOL.

1

Éste no se romperá para un archivo de 1 o 0 líneas.

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 porque la última carbón puede ser \n

1

... ¿Por qué acaba de leer la última línea?

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

¿Porque eso es lo que necesitaba el OP? lol – dtbarne

0

@unique_stephen, su respuesta no es válida. PHP fseek devuelve 0 para el éxito y -1 para el fracaso. Almacenar el resultado en $ begining (sic) y luego usarlo en un filtro para ftell() no es correcto. Si mi reputación fuera más alta, te habría votado negativamente y habría dejado un comentario. Aquí hay una versión modificada de la función de 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; 
} 

NOTA: fseek de PHP no puede manejar a buscar hasta el final de archivos de más de PHP_MAX_INT que es de 32 bits firmado incluso en los binarios de 64 bits.

+1

Esto no proporciona una respuesta a la pregunta. Una vez que tenga suficiente [reputación] (https://stackoverflow.com/help/whats-reputation) podrá [comentar cualquier publicación] (https://stackoverflow.com/help/privileges/comment); en su lugar, [brinde respuestas que no requieran aclaración del autor de la pregunta] (https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can- i-do-instead). - [De la crítica] (/ review/low-quality-posts/18923154) –

+0

Sí, ya hay respuestas a la pregunta.El problema de no poder dejar un comentario sobre una respuesta es lo que debe resolverse si no quiere que deje una respuesta como comentario. Editaré la respuesta para dar una versión correcta de la respuesta de @ unique_stephen. – Earnie

Cuestiones relacionadas