2010-04-08 32 views
7

Tengo un archivo de 200kb, lo que uso en varias páginas, pero en cada página necesito solo 1-2 líneas de ese archivo, así que ¿cómo puedo leer solo estas líneas si necesito el número de línea?Cómo guardar memoria al leer un archivo en Php?

Por ejemplo, si solo necesito la 10ma línea, no quiero cargar en la memoria todas las líneas, solo la décima línea.

Lo siento por mi mal inglés!

Respuesta

3

A menos que sepa el desplazamiento de la línea, tendrá que leer cada línea hasta ese punto. Puedes descartar las líneas antiguas (que no deseas) al recorrer el archivo con algo como fgets(). (EDIT: En lugar de fgets(), sugeriría @Gordon 's solution)

Posiblemente una mejor solución sería utilizar una base de datos, como el motor de base de datos va a hacer el trabajo sucio de almacenar las cuerdas y le permitirá (de manera muy eficiente) obtener una cierta "línea" (no sería una línea sino un registro con una identificación numérica, sin embargo, equivale a lo mismo) sin tener que leer los registros anteriores.

+0

Por favor comente en el Votación – Yacoby

+0

Esa base de datos será más rápida es subjetiva. Si la información a la que está intentando acceder está en el comienzo del archivo, será mucho más rápida. La lectura desde una base de datos todavía está leyendo desde un archivo. Mejorará el índice de la base de datos solo si está buscando algo que esté lejos del comienzo de su archivo. También depende de lo que intenta lograr exactamente. –

+2

Nunca dijo que la base de datos sería más rápida. Solo que sería mejor. La preocupación del PO podría verse como un problema de memoria más que de velocidad. – webbiedave

0

Simplemente recorra sin almacenar, p. Ej.

$i = 1; 
$file = fopen('file.txt', 'r'); 
while (!feof($file)) { 
    $line = fgets($file); // this gets whole line from the file; 
    if ($i == 10) { 
     break; // break on tenth line 
    } 
    $i ++; 
} 

El ejemplo anterior podría mantener la memoria de sólo la última línea se puso desde el archivo, por lo que esta es la manera más eficiente de la memoria más para hacerlo.

+1

1. te olvidas $ i ++, 2. ¿por qué no solo compruebas si $ i == 10? – zerkms

+0

Bleh, siempre me olvido de poner los incrementos. En cuanto a == 10 ... otra vez, un mal habito de analizar demasiadas cosas con repeticiones ... realmente lo siento, reparado :) – bisko

+0

stream_get_line() es más rápido que fgets() –

0

use fgets(). 10 veces :-) en este caso no almacenará las 10 líneas en la memoria

1
<?php 
    $lines = array(1, 2, 10); 

    $handle = @fopen("/tmp/inputfile.txt", "r"); 
    if ($handle) { 
     $i = 0; 
     while (!feof($handle)) { 
      $line = stream_get_line($handle, 1000000, "\n"); 

      if (in_array($i, $lines)) { 
       echo $line; 
          $line = ''; // Don't forget to clean the buffer! 
      } 

      if ($i > end($lines)) { 
       break; 
      } 

      $i++; 
     } 
     fclose($handle); 
    } 
?> 
19

Trate SplFileObject

echo memory_get_usage(), PHP_EOL;  // 333200 

$file = new SplFileObject('bible.txt'); // 996kb 
$file->seek(5000);      // jump to line 5000 (zero-based) 
echo $file->current(), PHP_EOL;   // output current line 

echo memory_get_usage(), PHP_EOL;  // 342984 vs 3319864 when using file() 

para la salida de la línea actual, puede utilizar current() o simplemente echo $file. Sin embargo, me parece más claro usar el método. También puede usar fgets(), pero eso obtendría la siguiente línea.

Por supuesto, solo necesita las tres líneas centrales. He agregado las llamadas memory_get_usage solo para demostrar que este enfoque casi no consume memoria.

+0

Agradable. No me di cuenta de que 'buscar' era una línea en lugar de un byte. – Yacoby

+0

+1 Prefiero este código porque es menos trabajo para el programador, y está más claro lo que está sucediendo (buscando cierta línea) que 'fgets'. – notJim

+0

@Yacoby hay 'SplFileInfo :: fseek()' y 'SplFileInfo :: seek()'. El último está basado en línea, el otro está basado en bytes. 'seek()' es un método de la interfaz 'SeekableIterator'. – Gordon

0

¿Por qué solo intenta cargar las primeras diez líneas? ¿Sabes que cargar todas esas líneas es, de hecho, un problema?

Si no ha medido, entonces no sabe que es un problema. No pierdas tu tiempo optimizando para no tener problemas. Lo más probable es que cualquier cambio en el rendimiento que tenga al no cargar todo el archivo de 200K sea imperceptible, a menos que sepa con certeza que cargar ese archivo es un cuello de botella.

2

¿Cambia el contenido del archivo? Si es estático o relativamente estático, puede crear una lista de compensaciones donde quiera leer sus datos. Por ejemplo, si el archivo cambia una vez al año, pero lo leen cientos de veces al día, a continuación, se puede pre-calcular las compensaciones de las líneas que desea y saltar directamente a ellos de esta manera:

$offsets = array(); 
while ($line = fread($filehandle)) { .... find line 10 .... } 
$offsets[10] = ftell($filehandle); // store line 10's location 
.... find next line 
$offsets[20] = ftell($filehandle); 

y pronto. Después, puede saltar trivialmente a la ubicación de esa línea como esta:

$fh = fopen('file.txt', 'rb'); 
fseek($fh, $offsets[20]); // jump to line 20 

pero esto podría ser un exceso en su totalidad.Intente comparar las operaciones: compare el tiempo que lleva realizar una "lectura de 20 líneas" anticuada versus precomputar/saltar.

Cuestiones relacionadas