Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to save memory when reading a file in Php?

I have a 200kb file, what I use in multiple pages, but on each page I need only 1-2 lines of that file so how I can read only these lines what I need if I know the line number?

For example if I need only the 10th line, I don`t want to load in memory all the lines, just the 10th line.

Sorry for my bad english!

like image 349
coolboycsaba Avatar asked Apr 08 '10 22:04

coolboycsaba


3 Answers

Try 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()

For outputting the current line, you can either use current() or just echo $file. I find it clearer to use the method though. You can also use fgets(), but that would get the next line.

Of course, you only need the middle three lines. I've added the memory_get_usage calls just to prove this approach does eat almost no memory.

like image 174
Gordon Avatar answered Nov 11 '22 03:11

Gordon


Unless you know the offset of the line, you will need to read every line up to that point. You can just throw away the old lines (that you don't want) by looping through the file with something like fgets(). (EDIT: Rather than fgets(), I would suggest @Gordon's solution)

Possibly a better solution would be to use a database, as the database engine will do the grunt work of storing the strings and allow you to (very efficiently) get a certain "line" (It wouldn't be a line but a record with an numeric ID, however it amounts to the same thing) without having to read the records before it.

like image 42
Yacoby Avatar answered Nov 11 '22 01:11

Yacoby


Do the contents of the file change? If it's static, or relatively static, you can build a list of offsets where you want to read your data. For instance, if the file changes once a year, but you read it hundreds of times a day, then you can pre-compute the offsets of the lines you want and jump to them directly like this:

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

and so on. Afterwards, you can trivially jump to that line's location like this:

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

But this could entirely be overkill. Try benchmarking the operations - compare how long it takes to do an oldfashioned "read 20 lines" versus precompute/jump.

like image 2
Marc B Avatar answered Nov 11 '22 02:11

Marc B