PHP
downloads | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

fstat> <fscanf
Last updated: Mon, 26 Nov 2007

view this page in

fseek

(PHP 4, PHP 5)

fseek — 在文件指针中定位

说明

int fseek ( resource $handle , int $offset [, int $whence ] )

在与 handle 关联的文件中设定文件指针位置。新位置从文件头开始以字节数度量,是以 whence 指定的位置加上 offsetwhence 的值定义为:

  • SEEK_SET - 设定位置等于 offset 字节。
  • SEEK_CUR - 设定位置为当前位置加上 offset
  • SEEK_END - 设定位置为文件尾加上 offset 。(要移动到文件尾之前的位置,需要给 offset 传递一个负值。)

如果没有指定 whence ,默认为 SEEK_SET

成功则返回 0;否则返回 -1。注意移动到 EOF 之后的位置不算错误。

Example#1 fseek() 例子

<?php

$fp 
fopen('somefile.txt''r');

// read some data
$data fgets($fp4096);

// move back to the begining of the file
// same as rewind($fp);
fseek($fp0);

?>

可能不能用于在 fopen() 中以 "http://" 或 "ftp://" 格式打开所返回的文件指针。在附加模式(加参数 "a" 打开文件)中 ftell() 会返回未定义错误。

Note: whence 参数是 PHP 4.0.0 之后增加的。

Note: 如果使用附加模试("a" 或 "a+"),任何写入文件数据都会被附加上去,而文件的位置将会被忽略。

参见 ftell()rewind()



fstat> <fscanf
Last updated: Mon, 26 Nov 2007
 
add a note add a note User Contributed Notes
fseek
mike at mike-miles dot com
14-Jun-2008 04:12
After not finding a good way to search a file backwards, I came up with this function, which uses fseek to scan the file backward byte by byte.

It returns the position of the last occurance of the search string, or FALSE if not found.  It's a case sensative search, but that could easily be changed.

<?php

function searchFromEnd($filename,$search){
    if(
file_exists($filename) && is_readable($filename)){ //first make sure that the file is there, and we can read it
       
$fp = fopen($filename,'r'); //open the file for reading
       
$size=strlen($search)-1; //get the length of the search string(minus the first character)
       
$first=$search[0]; //get first element in string
       
$file_size=filesize($filename); //size of the file
       
$seek=$file_size-$size; //set seek pointer to end of the file - size of the string
       
$found=false; //set found to FALSE
       
       
while($seek>=0){ //while not past the begining of the file
           
fseek($fp,$seek); //set file pointer to seek value
           
$test=fread($fp,1); //read in the first byte from pointer
           
if($test==$first && (($seek+$size) <= $file_size) ){ //if byte is same as the first string character, and  back far enough in file for search length
               
$test.=fread($fp,$size); //append enough characters to $test to make it same size as $search
               
               
if(strcmp($test,$search)==0){ //if test value is what we're looking for
                   
$found=$seek; //return position;
                   
$seek=-1; //set pointer to -1 (exit loop);
               
}else{
                   
$seek--; //move back a byte
               
}   

            }else{
               
$seek--; //move back a byte
           
}
        }
       
fclose($fp); //close the file   
   
}
    return
$found; //return FALSE or position of search string
}

?>

please, e-mail me and let me know if you find this function useful at all, or have any ideas on how to modify it
Anonymous
12-Apr-2008 01:45
To:seeker at example com
Be careful, though.
You can freely position you pointer if you open a file in (r+) mode, but it will "overwrite" the data, not "append it".

Tested this:

<?php
// file.txt content:
// "You can contribute your notes to the PHP manual from the comfort of your browser!"

$handler = fopen("file.txt", "r+");
fseek($handler, 0);
fwrite($handler, "want to add this");
?>
New contents of the file.txt will be like this:
"want to add thiste your notes to the PHP manual from the comfort of your browser!".

If you really want to append at the beginning, you have to first get all the contents, save it, clear the file, put the new contents and append the saved contents at the end.
seeker at example com
29-Feb-2008 12:40
JUST TO QUOTE AND POINT THIS OUT:

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
3. if you're using fseek() to write data to a file, remember to open the file in "r+"
mode, example:

  $fp=fopen($filename,"r+");

DON'T open the file in mode "a" (for append), because it puts
 the file pointer at the end of the file and doesn't let you
fseek earlier positions in the file (it didn't for me!). Also,
don't open the file in mode "w" -- although this puts you at
the beginning of the file -- because it wipes out all data in
the file.

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Took me half a day to figure :/
mhinks at gmail dot com
27-Feb-2007 03:38
Here's a function I wrote to binary search for a line of text within a file, particularly useful when the file is too large to read into memory at once and you want a faster search than linear.

function binary_search_in_file($filename, $search) {

    //Open the file
    $fp = fopen($filename, 'r');

    //Seek to the end
    fseek($fp, 0, SEEK_END);

    //Get the max value
    $high = ftell($fp);
   
    //Set the low value
    $low = 0;

    while ($low <= $high) {
        $mid = floor(($low + $high) / 2);  // C floors for you

        //Seek to half way through
        fseek($fp, $mid);

        if($mid != 0){
            //Read a line to move to eol
            $line = fgets($fp);
        }
       
        //Read a line to get data
        $line = fgets($fp);
       

        if ($line == $search) {
            fclose($fp);
            return $line;
        }
        else {
            if ($search < $line) {
                $high = $mid - 1;
            }
            else {
                $low = $mid + 1;
            }
        }
    }

    //Close the pointer
    fclose($fp);

    return FALSE;

}
marc dot roe at gmail dot com
20-Aug-2006 12:38
I tried to improve and modify (mail at ulf-kosack dot de)'s function. Actually it is very fast, i.e. requires much less time than to get the last five, ten or whatever lines of a file using file() ore file_get_contents().

function read_file($file, $lines)
{
       $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); // array_reverse is optional: you can also just return the $text array which consists of the file's lines.
}

The good thing now is, that you don't get an error when your requesting more lines than the file contains. In this case the function will just return the whole file content.
lucky at somnius dot com dot ar
19-Aug-2006 08:35
Jim's (jim at lfchosting dot com) code for the last-line issue is perfect if the file is not empty, or moreover if it has more than one line. However if the file you're using cotains no new-line character at all (i.e. it is empty or it's got one line and only one) the while loop will stuck indefinitely.

I know this script is meant for big files which would always contain at least several lines, but it would be clever to make the script error-proof.

Thus, here's a little modification to his code.

<?php
function readLastLine ($file) {
   
$fp = @fopen($file, "r");

   
$pos = -1;
   
$t = " ";
    while (
$t != "\n") {
        if (!
fseek($fp, $pos, SEEK_END)) { // *** - fseek returns 0 if successfull, and -1 if it has no succes as in seeking a byte outside the file's range
           
$t = fgetc($fp);
           
$pos = $pos - 1;
        } else {
// ***
           
rewind($fp); // ***
           
break; // ***
       
} // ***
   
}
   
$t = fgets($fp);
   
fclose($fp);
    return
$t;
}
?>

Lines added and/or modified have been marked with "// ***". I hope this helps!

Regards!
mail at ulf-kosack dot de
28-May-2006 01:44
Here a little extension for the code of ekow.
If you want to read more than one line and more than one file. Some times the last five ore ten lines are interesting in.

You only have to submit a array with filenames and optionally a number of lines you want to read.

<?php
 
function read_logfiles($files, $lines=5)
  {
    foreach(
$files as $file_num => $file) {
      if (
file_exists ($file) ) {
       
$handle = fopen($file, "r");
       
$linecounter = $lines;
       
$pos = -2;
       
$t = " "
       
$text[$file_num] = "";
        while (
$linecounter > 0) {
          while (
$t != "\n") {
           
fseek($handle, $pos, SEEK_END);
           
$t = fgetc($handle);
           
$pos --;
          }
         
$t = " ";
         
$text[$file_num] .= fgets($handle);
         
$linecounter --;
        }
       
fclose ($handle);
      } else {
       
$text[$file_num] = "The file doesn't exist.";
      }
    }
   
    return
$text;
?>
ekow[at]te.ugm.ac.id
11-Dec-2005 09:22
A little correction for code to read last line from chenganeyou at eyou dot com.
$linenumber = sizeof($file)-1;
should be
$linenumber = sizeof($contents)-1;
because sizeof will count array element, not file size.
<?php
function readlastline($file)
{
      
$linecontent = " ";
      
$contents = file($file);
      
$linenumber = sizeof($contents)-1;
      
$linecontet = $contents[$linenumber];
       unset(
$contents,$linenumber);
       return
$linecontent;
}
?>
jeffunk7 at yahoo dot com
10-Dec-2005 10:46
If you, like me, need the second to last line from a text file (or some other line near the end that you will know the number of, ie the fourth to last line) then this addition to Jim's code can help you.

//$linefromlast is the linenumber that you need, the last line being 1, the second to last being 2, and so on...

function readlog($file, $linefromlast){
   $fp = @fopen($file, "r");
   $pos = -2;
   $t = " ";
   $linecounter = 1;
        while ($t != "\n" and $linecounter<=$linefromlast) {
                fseek($fp, $pos, SEEK_END);
                $t = fgetc($fp);
                $pos = $pos - 1;
                if ($t == "\n" and $linecounter < $linefromlast) {
                        fseek($fp, $pos, SEEK_END);
                        $t = fgetc($fp);
                        $pos = $pos - 1;
                        $linecounter = $linecounter +1;
                }
         }
    $t = fgets($fp);
    fclose($fp);
    return $t;
}
memphis
23-Jul-2005 04:41
Actually chenganeyou, your function causes the entire file to be read into an array, and then you look at the last element of the array.  While this works fine for a small file, an sizeable file is going to suck down memory and time.  Using a 15 MB file your function took around 2 secs to return.

The function provided by Jim goes directly to the end of the file and only reads in that line.  I had to set the offset ($pos) to -2 for it to work in my case however.  Using the same 15 MB file this function returns immediately.
chenganeyou at eyou dot com
27-Jun-2005 04:35
I use the following codes to read the last line of a file.
Compared to jim at lfchosting dot com, it should be more efficient.

<?php
function readlastline($file)
{
      
$linecontent = " ";
      
$contents = file($file);
      
$linenumber = sizeof($file)-1;
      
$linecontet = $contents[$linenumber];
       unset(
$contents,$linenumber);
       return
$linecontent;
}
?>
phil at NOSPAM dot blisswebhosting dot com
26-May-2005 11:43
In order to read a text file from end->beginning e.g display the most recent contents of a log file first.  I use the following.

It basically just uses fseek to find the end of the file, ftell to find the byte count for a counter, then iterates backwards through the file using fgetc to test for the newline charater.

$i=0 ;
$lines=500 ;
$fp = fopen($log,"r") ;
if(is_resource($fp)){
    fseek($fp,0,SEEK_END) ;
    $a = ftell($fp) ;
    while($i <= $lines){
        if(fgetc($fp) == "\n"){
            echo (fgets($fp));
            $i++ ;
        }
    fseek($fp,$a) ;
    $a-- ;
    }
}
alan at peaceconstitution.com
18-May-2005 09:03
Thanks to Dan, whose above comment provided a key to solve the issue of how to append to a file.
     After, using phpinfo(); I made sure my installation of PHP had the requisite settings mentioned in the text to the manual entry for fopen(), I was puzzled as to why my use of fopen() with the append option 'a' (append option) didn't work. Then I  read a comment contributed to Appendix L (http://us2.php.net/manual/en/wrappers.php) that the append option 'a' for fopen() doesn't work as expected. The writer suggested using the 'w' option instead, which I found did work. But the 'w' option (write option) overwrites everything in the file.
     The question remained how to accomplish appending. Following Dan's suggestion about the 'r+' option, I tried this, which works fine:
       $string = "Message to write to log";
       $filehandle = fopen ("/home/name/sqllogs/phpsqlerr.txt", 'r+');
    fseek ( $filehandle,0, SEEK_END);
    fwrite ( $filehandle, $string."\n" );
    fclose ($filehandle);
Lutz ( l_broedel at gmx dot net )
15-Feb-2005 06:25
Based on the function below, provided by info at o08 dot com (thanks), the following should enable you to read a single line from a file, identified by the line number (starting with 1):

<?
    function readLine ($linenum,$fh) {
        $line = fgets ($fh, 4096);
        $pos = -1;
        $i = 0;

        while (!feof($fh) && $i<($linenum-1)) {
            $char = fgetc($fh);
            if ($char != "\n" && $char != "\r") {
                fseek($fh, $pos, SEEK_SET);
                $pos ++;
            }
            else $i ++;
        }
        $line = fgets($fh);
        return $line;
    } //readLine()
?>
info at o08 dot com
16-Feb-2004 03:27
I think the function should be as following to deal any combination of cr & lf, no matter the line ends by cr, lf, cr-lf or lf-cr:

<?php
function getline ($handle) {
       while (!
feof($handle)) {
          
$char = fgetc($handle);
           if ((
$char == "\n") or ($char == "\r")) {
              
$char2 = fgetc($handle);
               if ((
$char2 != "\n") && ($char2 != "\r")) {
                  
fseek ($handle,-1,SEEK_CUR);
               }
               break;
           }
           else {
              
$buffer .= $char;
           }
       }
       return
$buffer;
}
?>
jim at lfchosting dot com
05-Nov-2003 10:03
Here is a function that returns the last line of a file.  This should be quicker than reading the whole file till you get to the last line.  If you want to speed it up a bit, you can set the $pos = some number that is just greater than the line length.  The files I was dealing with were various lengths, so this worked for me.

<?php
function readlastline($file)
{
       
$fp = @fopen($file, "r");
       
$pos = -1;
       
$t = " ";
        while (
$t != "\n") {
             
fseek($fp, $pos, SEEK_END);
             
$t = fgetc($fp);
             
$pos = $pos - 1;
        }
       
$t = fgets($fp);
       
fclose($fp);
        return
$t;
}
?>
aspyrine at hotmail dot com
11-Mar-2003 11:51
If you want to go to the end of a socket stream with fseek() you'll get the following error :
"stream does not support seeking"

feof() wont work eiver in a stream (ie. smtp)

You can move the pointer to the end with this command :
while(fgetc($fp)) {}
...so easy :-)
17-Sep-2002 04:25
Don't use filesize() on files that may be accessed and updated by parallel processes or threads (as the filesize() return value is maintained in a cache).
Instead lock the opened file and use fseek($fp,0,SEEK_END) and ftell($fp) to get the actual filesize if you need to perform a fread() call to read the whole file...
25-Aug-2002 08:12
The following call moves to the end of file (i.e. just after the last byte of the file):

fseek($fp, 0, SEEK_END);

It can be used to tell the size of an opened file when the file name is unknown and can't be used with the filesize() function:

fseek($fp, 0, SEEK_END);
$filesize = ftell($fp);

The following call moves to the begining of file:

fseek($fp, 0, SEEK_SET);

It is equivalent to:

rewind($fp);
dan at daniellampert dot com
02-Jan-2002 06:54
For all first-time users of the fseek() function, remember these three things:

1. to use a programming expression, fseek() is "base 0", so to prepare the file for writing at character 1, you'd say fseek($fp,0); and to prepare the file for writing at character $num, you'd say fseek($fp,($num-1));

2. here's the formula for accessing fixed-length records in a file (you need to seek the position of the end of the previous record):

  /* assumes the desired record number is in $rec_num */
  /* assumes the record length is in $rec_len */
  $pos = ( ($rec_num-1) * $rec_len );
  fseek($fp,$pos);

3. if you're using fseek() to write data to a file, remember to open the file in "r+" mode, example:

  $fp=fopen($filename,"r+");

Don't open the file in mode "a" (for append), because it puts the file pointer at the end of the file and doesn't let you fseek earlier positions in the file (it didn't for me!). Also, don't open the file in mode "w" -- although this puts you at the beginning of the file -- because it wipes out all data in the file.

Hope this helps.

fstat> <fscanf
Last updated: Mon, 26 Nov 2007
 
 
show source | credits | sitemap | contact | advertising | mirror sites