1

I have a file arranged like so:
"url1","info1"
"url2","info2"
"url3","info3" ... all the way up to "url15","info15"

I would like to read the last 10 lines of the file into an array such that $pagelist[0][0] would give url5 and $pagelist[0][1] would give info5.

My current code is as follows:

$file=fopen(csvfile.txt,"r");
$pagelist=array();
$i=0;
$key=0;
while (!feof($file)) {
    if ($i >= (count($file)-11)) {
        $pagelist[$key]=fgetcsv($file);
        $key++; }
    $i++;
}
fclose($file)

When I used print_r($pagelist) it seemed to have loaded all the lines of the file into the array instead of just the last 10. Can anyone see what I've done wrong in my code? thanks :)

3 Answers 3

3

The problem with you code is that count($file) is not doing what you think. $file is just a file handle resource, not an array. You end up comparing $i >= -11, which will of course always evaluate to true/

You might try something like this if you want to just use linux to grab the last ten lines (not sure if you are on linux):

$initial_csv = 'csvfile.txt';
$truncated_csv ='csvfile_trun';
$number_of_lines_from_end = 10;
shell_exec('tail -n ' . $number_of_lines_from_end . ' ' . $initial_csv . ' > ' . $truncated_csv);
$file=fopen($truncated_csv,"r");
$pagelist=array();
$i=0;
while (!feof($file)) {
    $pagelist[$i]=fgetcsv($file);
    $i++;
}
fclose($file)

Alternatively, if you don't mind having the entire file in memory (i.e. the file will remain small), you can read the entire file into an array like this.

$csv = 'csvfile.txt';
$number_of_lines_from_end = 10;
$file_array = file($csv);
$line_count = count($file_array);
$start = $line_count - $number_of_lines_from_end - 1;
$pagelist=array();
for ($i = $start; $i < $line_count; $i++) {
    $pagelist[]=fgetcsv($file);
}
Sign up to request clarification or add additional context in comments.

8 Comments

If going the file() route (huge memory indeed), an foreach(array_slice($file_array,$line_count-11,10) as $line) $pagelist[]=str_getcsv($line); seems more apt.
@Wrikken The only reason I provided the file() solution is that it seems the OP is dealing with relatively little data. If you were talking about thousands of line of data, I would use something like the linux tail command to solution to just get the portion of the data is cared about right up front. You are right that array_slice() would work fine just as well.
Just to clarify, the array_slice doesn't address the memory issue; the use of file() means that the file is already read into memory. array_slice just avoids looping through the first n-10 lines.
@ernie You are correct about the memory consumption. The code shown does not loop through the first n-10 lines, however.
Yes, I wouldn't advocate file() for a couple of MBs of logfiles for instance, I was just saying that if we have it, we might as well use it (and your code misses a seeking to the proper line in that part b.t.w.). If I was the OP, I'd go for the tail solution most definitely (with proper escapeshellarg for dynamic arguments).
|
0

Yet another implementation, for the fun of it (Mike's tail is probably fastest):

$storage  = new SPLFixedArray(10);
$i = 0;
while(($line = fgets($file)) && ++$i) {
    $storage[$i%10] = $line;
}
$storage = $storage->toArray();
//switch if order is important;
$prepend = array_splice($storage,($i%10)+1,10 - ($i%10));
array_splice($storage,0,0,$prepend);
//interpret csv
$result = array_map('str_getcsv',$storage);

1 Comment

FWIW, a simple 1M lines seems to take about 2 seconds here. Fast enough for shell scripts / crons, waaaaaay to long for HTTP requests.
-1
$file=fopen(csvfile.txt,"r");    
$pagelist= [];                  
$temp = fgetcsv($file);          
array_merge($pagelist, $temp);   
fclose($file);                              
print_r($pagelist);                         
$lastten = array_slice($pagelist, -10, 10); 
print_r($lastten);

*I might be wrong about the slice offset and limit.

1 Comment

You need a loop for fgetcsv as it reads only a single line from the file.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.