¿Cómo se lee un archivo revés línea por línea usando fseek?Leer un archivo línea por línea hacia atrás usando fseek
código puede ser útil. debe ser multiplataforma y php puro
muchas gracias de antemano
que respecta a
Jera
¿Cómo se lee un archivo revés línea por línea usando fseek?Leer un archivo línea por línea hacia atrás usando fseek
código puede ser útil. debe ser multiplataforma y php puro
muchas gracias de antemano
que respecta a
Jera
La pregunta es preguntar usando fseek, por lo que solo podemos suponer que el rendimiento es un problema y file() no es la solución. Aquí es un enfoque simple usando fseek:
Mi archivo.txt
#file.txt
Line 1
Line 2
Line 3
Line 4
Line 5
Y el código:
<?php
$fp = fopen('file.txt', 'r');
$pos = -2; // Skip final new line character (Set to -1 if not present)
$lines = array();
$currentLine = '';
while (-1 !== fseek($fp, $pos, SEEK_END)) {
$char = fgetc($fp);
if (PHP_EOL == $char) {
$lines[] = $currentLine;
$currentLine = '';
} else {
$currentLine = $char . $currentLine;
}
$pos--;
}
$lines[] = $currentLine; // Grab final line
var_dump($lines);
Salida:
array(5) {
[0]=>
string(6) "Line 5"
[1]=>
string(6) "Line 4"
[2]=>
string(6) "Line 3"
[3]=>
string(6) "Line 2"
[4]=>
string(6) "Line 1"
}
Usted no tiene que anexar a la matriz de $ lines como soy, puede imprimir la salida de inmediato si ese es el propósito de su secuencia de comandos. También es fácil introducir un contador si desea limitar el número de líneas.
$linesToShow = 3;
$counter = 0;
while ($counter <= $linesToShow && -1 !== fseek($fp, $pos, SEEK_END)) {
// Rest of code from example. After $lines[] = $currentLine; add:
$counter++;
}
Después de rechazar mi edición ...: Debe verificar si el manejador de archivos es válido después de fopen() y luego libre con fclose() para liberarlo y evitar pérdidas de memoria. – StanE
PHP_EOL depende de la plataforma y en algunos casos será insuficiente. Reemplazar la condición con ... ("\ n" == $ char) ... y omitir las líneas vacías lo hará más confiable – ANTARA
No se puede fseek línea por línea, ya que no se sabe cuánto tiempo las líneas son hasta que las lee.
Debe leer todo el archivo en una lista de líneas, o si el archivo es demasiado grande para eso y solo necesita las últimas líneas, leer fragmentos de tamaño fijo desde el final del archivo e implementar un poco más lógica complicada que detecta líneas de tales datos.
Si va a leer el archivo completo de todos modos, simplemente use file() para leer el archivo como una matriz (cada línea es cada elemento de la matriz) y luego use array_reverse() para voltear la matriz hacia atrás y recorrerla . O simplemente haz un reverse para loop donde comiences al final y decrementa en cada loop.
$file = file("test.txt");
$file = array_reverse($file);
foreach($file as $f){
echo $f."<br />";
}
O para evitar revertir la matriz, puede simplemente hacer un bucle desde $ i = count ($ file) - 1; $ i> 0; $ i ++) y lee $ file [$ i] –
@EqSum yep, puede hacer eso. La parte media del bucle for debería ser '$ i> = 0' sin embargo. –
¡Oye! Si está analizando un archivo realmente grande (millones de líneas), esto consumirá rápidamente mucha memoria al cargar todo en la memoria. ¡Esto no es una buena idea! –
Para revertir completamente un archivo:
$fl = fopen("\some_file.txt", "r"); for($x_pos = 0, $output = ''; fseek($fl, $x_pos, SEEK_END) !== -1; $x_pos--) { $output .= fgetc($fl); } fclose($fl); print_r($output);
Por supuesto, usted quiere línea por línea de reversión ...
$fl = fopen("\some_file.txt", "r"); for($x_pos = 0, $ln = 0, $output = array(); fseek($fl, $x_pos, SEEK_END) !== -1; $x_pos--) { $char = fgetc($fl); if ($char === "\n") { // analyse completed line $output[$ln] if need be $ln++; continue; } $output[$ln] = $char . ((array_key_exists($ln, $output)) ? $output[$ln] : ''); } fclose($fl); print_r($output);
Realmente sin embargo, Jonathan Kuhn tiene la mejor respuesta En mi humilde opinión arriba. Los únicos casos que no usaría su respuesta, que yo sepa si es file
o como funciones no están disponibles a través de php.ini, sin embargo, el administrador se olvidó de fseek, o al abrir un archivo enorme acaba de obtener las últimas líneas de contenidos mágicamente guardar la memoria de esta manera.
Nota: El manejo de errores no incluido. Y, PHP_EOL no cooperó, así que usé "\ n" para denotar el final de la línea. Por lo tanto, lo anterior puede no funcionar en todos los casos.
El código de la segunda parte, que analiza línea por línea, no funciona. –
Leyendo el archivo entero en una matriz y de marcha atrás está bien a menos que el archivo es enorme.
Usted puede realizar una lectura tamponada de su archivo de atrás hacia adelante con algo como esto:
<?php
class ReverseFile implements Iterator
{
const BUFFER_SIZE = 4096;
const SEPARATOR = "\n";
public function __construct($filename)
{
$this->_fh = fopen($filename, 'r');
$this->_filesize = filesize($filename);
$this->_pos = -1;
$this->_buffer = null;
$this->_key = -1;
$this->_value = null;
}
public function _read($size)
{
$this->_pos -= $size;
fseek($this->_fh, $this->_pos);
return fread($this->_fh, $size);
}
public function _readline()
{
$buffer =& $this->_buffer;
while (true) {
if ($this->_pos == 0) {
return array_pop($buffer);
}
if (count($buffer) > 1) {
return array_pop($buffer);
}
$buffer = explode(self::SEPARATOR, $this->_read(self::BUFFER_SIZE) . $buffer[0]);
}
}
public function next()
{
++$this->_key;
$this->_value = $this->_readline();
}
public function rewind()
{
if ($this->_filesize > 0) {
$this->_pos = $this->_filesize;
$this->_value = null;
$this->_key = -1;
$this->_buffer = explode(self::SEPARATOR, $this->_read($this->_filesize % self::BUFFER_SIZE ?: self::BUFFER_SIZE));
$this->next();
}
}
public function key() { return $this->_key; }
public function current() { return $this->_value; }
public function valid() { return ! is_null($this->_value); }
}
$f = new ReverseFile(__FILE__);
foreach ($f as $line) echo $line, "\n";
Este código lee el archivo al revés. Este código ignora las modificaciones en la lectura, ejemplo apache access.log nuevas líneas en procressing.
$f = fopen('FILE', 'r');
fseek($f, 0, SEEK_END);
$pos = ftell($f);
$pos--;
while ($pos > 0) {
$chr = fgetc($f);
$pos --;
fseek($f, $pos);
if ($chr == PHP_EOL) {
YOUR_OWN_FUNCTION($rivi);
$rivi = NULL;
continue;
}
$rivi = $chr.$rivi;
}
fclose($f);
¿Hay alguna razón por la que se debe buscar en lugar de las siguientes sugerencias que implican leer todo el archivo? ¿Qué tipo de datos estás leyendo? – salathe
Si desea más ** solución compatible con la memoria **, esta es una respuesta mía que responde una pregunta similar: http://stackoverflow.com/questions/20561480/read-file-lines-backwards-fgets-with-php/ 26595154 # 26595154 –