PHPのお勉強!

PHP TOP

fseek

(PHP 4, PHP 5, PHP 7, PHP 8)

fseekファイルポインタを移動する

説明

fseek(resource $stream, int $offset, int $whence = SEEK_SET): int

stream が指しているファイルのファイル位置識別子を ファイル・ストリーム中の offset バイト目に セットします。新規位置は、ファイルの先頭からのバイト数で 測られます。これは whence で指定した位置に offset を追加することにより得られます。

一般的に、ファイルの終端より先の位置に移動することも許されています。 そこにデータを書き込んだ場合、ファイルの終端からシーク位置までの範囲を読み込むと 値 0 が埋められたバイトを返します。しかし、ストリームの種類によっては この挙動をサポートしていないものもあります。 ストリームのもとになっているストレージが固定長である場合などです。

パラメータ

stream

fopen() を使用して作成したファイルシステムポインタリソース。

offset

オフセット。

ファイルの終端から数えた位置に移動するには、負の値を offset に渡して whenceSEEK_END に設定しなければなりません。

whence

whence の値は以下のようになります。

  • SEEK_SET - 位置を offset バイト目に設定する
  • SEEK_CUR - 現在の位置に offset を加えた位置に設定する
  • SEEK_END - ファイル終端に offset を加えた位置に設定する

戻り値

成功すると 0 を返し、そうでなければ -1 を返します。

例1 fseek() の例

<?php

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

// データを読み込む
$data = fgets($fp, 4096);

// ファイルの先頭に移動する。
// rewind($fp); と等価。
fseek($fp, 0);

?>

注意

注意:

追加モード (a あるいは a+) でファイルをオープンした場合、 ファイル位置によらず、ファイルに書き込むあらゆるデータが追加されます。また fseek() の結果は未定義となります。

注意:

すべてのストリームがシーク処理に対応しているわけではありません。 シークに対応していないストリームで現在位置から前方へのシークを行うには、 データを読み込んでそれを捨てていくしかありません。それ以外のやり方は失敗します。

参考

  • ftell() - ファイルの読み書き用ポインタの現在位置を返す
  • rewind() - ファイルポインタの位置を先頭に戻す

add a note

User Contributed Notes 26 notes

up
83
seeker at example com
16 years ago
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 :/
up
19
Anonymous
13 years ago
The official docs indicate that not all streams are seekable.
You can try to seek anyway and handle failure:

<?php
if (fseek($stream, $offset, SEEK_CUR) === -1) {
// whatever
}
?>

Or, you can use the stream_get_meta_data function:
http://php.net/stream_get_meta_data

<?php
function fseekable($stream) {
$meta = stream_get_meta_data($stream);
return
$meta['seekable'];
}
?>
up
16
lorenzo dot stanco at gmail dot com
11 years ago
I want to give my contribution about the "read last lines from a file" topic. I've done some researches (starting from here, really) and run many tests for different algorithms and scenarios, and came up with this:

What is the best way in PHP to read last lines from a file?
http://stackoverflow.com/a/15025877/995958

In that mini-article I tried to analyze all different methods and their performance over different files.

Hope it helps.
up
6
marc dot roe at gmail dot com
18 years ago
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.
up
11
synnus at gmail dot com
10 years ago
Write Dummy File 4GB in Php 32bits (X86)
if you want write more GB File (>4GB), use Php(X64) .
this file is created in 0.0041329860687256 second

CreatFileDummy('data_test.txt',4294967296);

FUNCTION CreatFileDummy($file_name,$size) {
// 32bits 4 294 967 296 bytes MAX Size
$f = fopen($file_name, 'wb');
if($size >= 1000000000) {
$z = ($size / 1000000000);
if (is_float($z)) {
$z = round($z,0);
fseek($f, ( $size - ($z * 1000000000) -1 ), SEEK_END);
fwrite($f, "\0");
}
while(--$z > -1) {
fseek($f, 999999999, SEEK_END);
fwrite($f, "\0");
}
}
else {
fseek($f, $size - 1, SEEK_END);
fwrite($f, "\0");
}
fclose($f);

Return true;
}

Synx
up
7
Anonymous
16 years ago
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.
up
4
Lutz ( l_broedel at gmx dot net )
19 years ago
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()
?>
up
3
Anonymous
22 years ago
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...
up
6
me at php dot net
11 years ago
how to read BIG files using fseek (above 2GB+, upto any size like 4GB+, 100GB+, 100 terabyes+, any file size, 100 petabytes, max limit is php_float_max ) ?

// seek / set file pointer to 50 GB
my_fseek($fp, floatval(50000000000),1);

function my_fseek($fp,$pos,$first=0) {

// set to 0 pos initially, one-time
if($first) fseek($fp,0,SEEK_SET);

// get pos float value
$pos=floatval($pos);

// within limits, use normal fseek
if($pos<=PHP_INT_MAX)
fseek($fp,$pos,SEEK_CUR);
// out of limits, use recursive fseek
else {
fseek($fp,PHP_INT_MAX,SEEK_CUR);
$pos -= PHP_INT_MAX;
my_fseek($fp,$pos);
}

}

hope this helps.
up
1
Tom Pittlik
15 years ago
The tail example functions below will return a PHP memory limit error when trying to open large files. Since tail is convenient for opening large logs, here is a function that lets you (provided you have permission):

<?php

function unix_tail($lines,$file)
{
shell_exec("tail -n $lines $file > /tmp/phptail_$file");
$output = file_get_contents("/tmp/phptail_$file");
unlink("/tmp/phptail_$file");
return
$output;
}

?>
up
1
kavoshgar3 at gmail dot com
13 years ago
sometimes we want read file from last line to beginning of file.I use the following.
<?php
function read_backward_line($filename, $lines, $revers = false)
{
$offset = -1;
$c = '';
$read = '';
$i = 0;
$fp = @fopen($filename, "r");
while(
$lines && fseek($fp, $offset, SEEK_END) >= 0 ) {
$c = fgetc($fp);
if(
$c == "\n" || $c == "\r"){
$lines--;
if(
$revers ){
$read[$i] = strrev($read[$i]);
$i++;
}
}
if(
$revers ) $read[$i] .= $c;
else
$read .= $c;
$offset--;
}
fclose ($fp);
if(
$revers ){
if(
$read[$i] == "\n" || $read[$i] == "\r")
array_pop($read);
else
$read[$i] = strrev($read[$i]);
return
implode('',$read);
}
return
strrev(rtrim($read,"\n\r"));
}
//if $revers=false function return->
//line 1000: i am line of 1000
//line 1001: and i am line of 1001
//line 1002: and i am last line
//but if $revers=true function return->
//line 1002: and i am last line
//line 1001: and i am line of 1001
//line 1000: i am line of 1000
?>
Enjoy! Mail me if it works! ;-)
up
1
Raven dot Singularity at NOSPAM dot gmail dot com
16 days ago
WARNING: The return values for this function are backwards from what is expected in PHP!

<?php

if (!fseek($File_Handle, $Position)) {
die(
"Could not seek in file.");
}

?>

This will die when it succeeds, and continue when it fails. This is because the return values for fseek() are backwards from other PHP functions. This function returns 0 (FALSE) on success, and -1 (TRUE) on failure.

This needs a big red warning box similar to other functions that return FALSE on failure and 0 or above on success. I submitted a documentation issue.

This works for checking for errors:

<?php

if (fseek($File_Handle, $Position) === -1) {
die(
"Could not seek in file.");
}

?>
up
0
marin at sagovac dot com
8 years ago
Seek to a line of code than break from while to improve performance. Seek to specific line using SEEK_SET and get a specific line. If $range is '0' than will show seeked line. If set to '2' it will show current line + 2 lines above + 2 lines below.

Useful for get a content of a file in very huge file to get lines range. To improve performance a while loop breaks from iteration than go for seeking.

I've created a function that read a file and count lines and store into arrays each lines bytes to seek. If maximum specified by `linenum` is set, it will break from while to keep performance than in a new loop function to seek a position in bytes to get a content of file.

function readFileSeek($source, $linenum = 0, $range = 0)
{
$fh = fopen($source, 'r');
$meta = stream_get_meta_data($fh);

if (!$meta['seekable']) {
throw new Exception(sprintf("A source is not seekable: %s", print_r($source, true)));
}

$pos = 2;
$result = null;

if ($linenum) {
$minline = $linenum - $range - 1;
$maxline = $minline+$range+$range;
}

$totalLines = 0;
while (!feof($fh)) {

$char = fgetc($fh);

if ($char == "\n" || $char == "\r") {
++$totalLines;
} else {
$result[$totalLines] = $pos;
}
$pos++;

if ($maxline+1 == $totalLines) {
// break from while to not read entire file
break;
}
}

$buffer = '';

for ($nr=$minline; $nr<=$maxline; $nr++) {

if (isset($result[$nr])) {

fseek($fh, $result[$nr], SEEK_SET);

while (!feof($fh)) {
$char = fgetc($fh);

if ($char == "\n" || $char == "\r") {
$buffer .= $char;
break;
} else {
$buffer .= $char;
}
}

}
}

return $buffer;
}

Test results (1.3 GB file, 100000000 lines of codes, seek to 300000 line a code):

string(55) "299998_abc
299999_abc
300000_abc
300001_abc
300002_abc
"

Time: 612 ms, Memory: 20.00Mb

$ ll -h /tmp/testfile
-rw-rw-r-- 1 1,3G /tmp/testfile
up
2
chenganeyou at eyou dot com
19 years ago
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;
}
?>
up
1
alan at peaceconstitution.com
19 years ago
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);
up
0
ben at nullcreations dot net
16 years ago
easier tail() function for php:

<?php
function tail($file, $num_to_get=10)
{
$fp = fopen($file, 'r');
$position = filesize($file);
fseek($fp, $position-1);
$chunklen = 4096;
while(
$position >= 0)
{
$position = $position - $chunklen;
if (
$position < 0) { $chunklen = abs($position); $position=0;}
fseek($fp, $position);
$data = fread($fp, $chunklen). $data;
if (
substr_count($data, "\n") >= $num_to_get + 1)
{
preg_match("!(.*?\n){".($num_to_get-1)."}$!", $data, $match);
return
$match[0];
}
}
fclose($fp);
return
$data;
}
?>
up
0
ekow[at]te.ugm.ac.id
19 years ago
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;
}
?>