fseek — Устанавливает смещение в файловом указателе

Функция fseek

Функция fseek() устанавливает указатель текущей позиции файла, связанного с потоком stream , в соответствии со значениями начала отсчета origin и смещения offset . Назначение этой функции — поддерживать операции ввода/вывода с произвольным доступом. Параметр offset равен количеству байтов, на которые будет смещен внутренний указатель файла относительно начала отсчета, заданного параметром origin . B качестве значения для параметра origin должен быть взят один из следующих макросов (определенных в заголовке ).

Имя Назначение
SEEK_SET Поиск с начала файла
SEEK_CUR Поиск с текущей позиции
SEEK_END Поиск с конца файла

Нулевое значение возврата свидетельствует об успешном выполнении функции fseek() , а ненулевое — о возникновении сбоя.

Вообще говоря, функцию fseek() следует использовать только при работе с двоичными файлами. При использовании же с текстовым файлом параметр origin должен иметь значение SEEK_SET , а параметр offset — значение, полученное в результате вызова функции ftell() для того же файла, или нуль (чтобы установить указатель текущей позиции файла на начало).

Функция fseek() очищает признак конца файла, связанный с заданным потоком. Более того, она аннулирует любой символ, ранее возвращенный в тот же поток через вызов функции ungetc() (см. раздел ungetc ).

Пример

Приведенная функция производит поиск заданной структуры, имеющей тип addr . Обратите внимание на использование оператора sizeof для получения размера структуры.

fseek передает отрицательное смещение и SEEK_CUR

У меня плохая производительность при запуске fseek(..) в очень большом файле. Каждый раз, когда вызывается функция fseek , мне нужно переместить позицию указателя файла назад на 100 bytes :

раньше я делал это:

Мой вопрос заключается в том, как fseek перемещает указатель через файл и устанавливает указатель файла в определенной позиции.

Я думал, что он берет указатель файла и перемещает его назад, но теперь я думаю, что он действительно

получить текущую позицию ( cp )

добавить отрицательный индекс ( p = idx + cp )

и переместить указатель файла из начала файла в эту позицию ( fseek(fp, p, SEEK_SET) )

2 ответа

На уровне пользовательского приложения вы рассматриваете файл как большой блок памяти и перемещаете указатель файла как простую операцию памяти (увеличивайте или уменьшайте указатель, чтобы получить желаемое смещение в файле).

Но в библиотеке времени выполнения и на уровне ОС все совершенно иначе. Код библиотеки времени выполнения, который обрабатывает файлы, не загружает все содержимое файла в память. Возможно, файл очень большой, может быть, вам нужно прочитать только пару байтов, есть много причин.

Библиотека времени выполнения (а также файловый кеш, управляемый ОС) загружает только некоторые данные из файла в буфер памяти. Вы работаете с этими данными (читаете их, записываете), и когда вы хотите получить доступ к информации, которая еще не загружена в буфер, код управления файлами загружает ее для вас; может быть, он увеличивает буфер или может записать буфер в файл (если он был изменен) или просто отбрасывает ранее загруженные данные (если он не был изменен) и загружает другой кусок данных в буфер.

Когда вы используете fseek() для перехода к другой части файла, обычно указатель файла попадает в область, которой еще нет в памяти. Я предполагаю, что он загружает данные, начиная с новой позиции указателя файла (на уровне операционной системы файловый кеш загружает данные в нескольких дисковых блоках). Поскольку вы запускаете файл в обратном направлении, я думаю, что данные в новой позиции указателя файла почти никогда не загружаются в память. Это вызывает доступ к диску, и это делает его медленным.

Я думаю, что лучшим решением для вас является использование функций, предоставляемых ОС, для сопоставления файла в памяти. Прочтите о mmap() в Linux (и, возможно, в OSX) или File Mapping в Windows. Это может помочь вам, но возможно, что улучшение не будет значительным из-за конкретной схемы доступа, которую вы используете. В большинстве случаев программы читают файл от начала до конца, и код, который имеет дело с файлами и доступом к диску, оптимизирован для этого шаблона.

Во-первых, какую операционную систему вы используете? Если это Linux, запустите ваше приложение под strace чтобы увидеть, какие системные вызовы оно на самом деле делает.

Во-вторых, fopen()/fseek()/fread() являются неправильными инструментами для этого шаблона доступа. Эти вызовы буферизуют файл для чтения — читая вперед . Это тебе не поможет. Вы используете fseek() для смещения X, любые буферизованные данные теперь бесполезны, вы fread() 100 байт, а буферизованный fread() читает больше — вероятно, 8 КБ. Вы, вероятно, читаете почти каждый байт файла более 80 раз. Вы можете использовать setbuf() или setvbuf() чтобы отключить буферизацию, но тогда вы будете выполнять 100-байтовые setvbuf() чтения при обратном просмотре файла. Это должно быть быстрее, но не так быстро, как вы можете идти.

Чтобы сделать это как можно быстрее (без использования многопоточного и / или асинхронного ввода-вывода):

Используйте open()/pread() . Вам не нужно искать — pread() читает напрямую с произвольного смещения.

Читайте большие куски — скажем, 8192 х 100. Или даже больше. Читайте в обратном порядке, как и раньше, но выполняйте буферизацию самостоятельно и начинайте со смещения в файле, кратном большому размеру, который вы читаете — первое чтение, вероятно, будет содержать менее 819 200 байт. Сначала обработайте последние 100 байтов в вашем буфере, а затем работайте в обратном направлении через буфер. Когда вы обработали первые 100 байтов в вашем буфере, используйте pread() чтобы прочитать предыдущие 819 200 байтов (или даже больше) из файла.

Используйте прямой IO, если доступно. Оптимизация файловой системы может попытаться «оптимизировать» ваш доступ, читая заранее и помещая данные в кэш страницы — данные, которые вы уже обработали. Поэтому по возможности обходите кеш страниц (не все операционные системы поддерживают прямой ввод-вывод, и не все файловые системы в ОС, поддерживающих прямой ввод-вывод, реализуют его).

Что-то вроде этого:

Вам нужно будет добавить обработку ошибок к этому.

fseek

Функция fseek() устанавливает указатель положения в файле, связанном со stream, в соответ­ствии со значениями offset и origin. Ее основное назначение — поддерживать операции ввода/ вывода по произвольному адресу. Аргумент offset — это выраженный в байтах сдвиг от позиции, определяемой origin, до новой позиции. Аргумент origin может принимать значения 0, 1 или 2, причем 0 означает начало файла, 1 — текущую позицию, а 2 — конец файла. В stdio.h определе­ны следующие макросы для origim

Имя Позиция origin
SEEK_SET Начало файла
SEEK_CUR Текущая позиция
SEEK_END Конец файла

В случае успеха fseek() возвращает 0. Ненулевое значение означает неудачу. С помощью fseek() можно переместить указатель положения в любую точку внутри файла и даже за его пределы после конца файла. Однако попытка установить указатель перед началом файла будет восприня­та как ошибка.

Функция fseek() сбрасывает флаг конца файла, связанный с указанным потоком. Кроме того, она обнуляет любую предыдущую ungetc() в том же потоке.

fseek, _fseeki64 fseek, _fseeki64

Перемещает файловый указатель в указанное местоположение. Moves the file pointer to a specified location.

Синтаксис Syntax

Параметры Parameters

вышестоящий stream
Указатель на структуру FILE. Pointer to FILE structure.

offset offset
Количество байт, начиная с origin. Number of bytes from origin.

origin origin
Первоначальная позиция. Initial position.

Возвращаемое значение Return Value

В случае успеха fseek и _fseeki64 возвращают 0. If successful, fseek and _fseeki64 returns 0. В противном случае возвращается ненулевое значение. Otherwise, it returns a nonzero value. Для устройств, которые не поддерживают поиск, возвращаемое значение не определено. On devices incapable of seeking, the return value is undefined. Если Stream является пустым указателем или если источник не является одним из допустимых значений, описанных ниже, fseek и _fseeki64 вызывают обработчик недопустимого параметра, как описано в разделе Проверка параметров. If stream is a null pointer, or if origin is not one of allowed values described below, fseek and _fseeki64 invoke the invalid parameter handler, as described in Parameter Validation. Если выполнение может быть продолжено, эти функции устанавливают значение еинвал и возвращают-1. If execution is allowed to continue, these functions set errno to EINVAL and return -1.

Примечания Remarks

Функции fseek и _fseeki64 перемещают указатель файла (при его наличии), связанный с потоком , в новое расположение, которое принимает байты из источника. The fseek and _fseeki64 functions moves the file pointer (if any) associated with stream to a new location that is offset bytes from origin. Следующая операция в потоке происходит в новом местоположении. The next operation on the stream takes place at the new location. В потоке, открытом для обновления, следующая операция может быть либо операцией чтения, либо операцией записи. On a stream open for update, the next operation can be either a read or a write. Источник аргумента должен быть одной из следующих констант, определенных в stdio. Высоты The argument origin must be one of the following constants, defined in STDIO.H:

значение происхождения origin value Значение Meaning
SEEK_CUR SEEK_CUR Текущая позиция файлового указателя. Current position of file pointer.
SEEK_END SEEK_END Конец файла. End of file.
SEEK_SET SEEK_SET Начало файла. Beginning of file.

Можно использовать fseek и _fseeki64 для перемещения указателя в любое место в файле. You can use fseek and _fseeki64 to reposition the pointer anywhere in a file. Указатель также может быть размещен за пределами файла. The pointer can also be positioned beyond the end of the file. fseek и _fseeki64 очищают индикатор конца файла и отменяют результат всех предыдущих вызовов ungetc в потоке. fseek and _fseeki64 clears the end-of-file indicator and negates the effect of any prior ungetc calls against stream.

Когда файл открыт для добавления данных, текущая позиция в файле определяется последней операцией ввода-вывода, а не тем, где должна произойти следующая запись. When a file is opened for appending data, the current file position is determined by the last I/O operation, not by where the next write would occur. Если в открытом для добавления файле еще не было ни одной операции ввода-вывода, этой позицией является начало файла. If no I/O operation has yet occurred on a file opened for appending, the file position is the start of the file.

Для потоков, открытых в текстовом режиме, fseek и _fseeki64 имеют ограниченный объем использования, так как переводы перевода строки с возвратом каретки могут привести к созданию непредвиденных результатов для fseek и _fseeki64 . For streams opened in text mode, fseek and _fseeki64 have limited use, because carriage return-line feed translations can cause fseek and _fseeki64 to produce unexpected results. Единственные операции fseek и _fseeki64 , которые гарантированно работают с потоками, открытыми в текстовом режиме,: The only fseek and _fseeki64 operations guaranteed to work on streams opened in text mode are:

поиск со смещением 0 относительно любого из значений origin; Seeking with an offset of 0 relative to any of the origin values.

Поиск с начала файла со значением offset, возвращенным из вызова ftell при использовании fseek или _ftelli64 при использовании _fseeki64. Seeking from the beginning of the file with an offset value returned from a call to ftell when using fseek or _ftelli64 when using _fseeki64.

Кроме того, в текстовом режиме при вводе CTRL+Z интерпретируется как символ конца файла. Also in text mode, CTRL+Z is interpreted as an end-of-file character on input. В файлах, открытых для операций чтения и записи, fopen и все связанные подпрограммы проверяют CTRL + Z в конце файла и удаляют его, если это возможно. In files opened for reading/writing, fopen and all related routines check for a CTRL+Z at the end of the file and remove it if possible. Это делается потому, что использование сочетания fseek и ftell или _fseeki64 и _ftelli64для перемещения внутри файла, заканчивающегося клавишами CTRL + Z, может вызвать неправильное поведение fseek или _fseeki64 в конце File. This is done because using the combination of fseek and ftell or _fseeki64 and _ftelli64, to move within a file that ends with a CTRL+Z may cause fseek or _fseeki64 to behave improperly near the end of the file.

Когда CRT открывает файл, который начинается с метки порядка байтов (BOM), указатель файла помещается после метки (т. е. в начале фактического содержимого файла). When the CRT opens a file that begins with a Byte Order Mark (BOM), the file pointer is positioned after the BOM (that is, at the start of the file’s actual content). Если необходимо fseek в начало файла, используйте ftell , чтобы получить начальное расположение и fseek на него, а не в положении 0. If you have to fseek to the beginning of the file, use ftell to get the initial position and fseek to it rather than to position 0.

Эта функция блокирует работу других потоков во время выполнения, поэтому она потокобезопасна. This function locks out other threads during execution and is therefore thread-safe. Описание неблокирующей версии этой функции см. в разделе _fseek_nolock, _fseeki64_nolock. For a non-locking version, see _fseek_nolock, _fseeki64_nolock.

Требования Requirements

Функция Function Обязательный заголовок Required header
fseek fseek
_fseeki64 _fseeki64

Дополнительные сведения о совместимости см. в разделе Совместимость. For additional compatibility information, see Compatibility.

SplFileObject::fseek

(PHP 5 >= 5.1.0, PHP 7)

SplFileObject::fseek — Перевод файлового указателя на заданную позицию

Описание

Перемещает файловый указатель на указанное в параметре offset количество байт. За позицию, от которой будет отсчитываться смещение отвечает параметр whence .

Список параметров

Смещение. Отрицательная величина смещения используется, когда нужно перемещаться по файлу от конца к началу, т.е. когда в качестве аргумента whence передано значение SEEK_END.

Возможные значения параметра whence :

  • SEEK_SET — Установить указатель на позицию offset байт от начала файла.
  • SEEK_CUR — Переместить указатель на offset байт относительно текущего положения.
  • SEEK_END — Установить указатель на позицию offset байт от конца файла.

Если параметр whence опущен, функция будет работать в режиме SEEK_SET .

Возвращаемые значения

Возвращает 0, если перемещение прошло успешно, и -1 в противном случае. Следует помнить, что перемещение за конец файла не рассматривается как ошибка.

Примеры

Пример #1 Пример использования SplFileObject::fseek()

= new SplFileObject ( «somefile.txt» );

// Чтение первой строки
$data = $file -> fgets ();

// Перемещаемся снова в начало файла
// То же, что и $file->rewind();
$file -> fseek ( 0 );
?>

Смотрите также

  • fseek() — Устанавливает смещение в файловом указателе

Что произойдет, если указанное смещение в fseek выходит за пределы последнего символа

В настоящее время я использую c ++ и пытаюсь написать файл, используя fseek (), чтобы записать заданное смещение, рассчитанное другими методами. Просто интересно, что произойдет, если данное смещение заставит указатель FILE выйти за пределы последнего символа в файле.

Пример:
Что будет возвращать fseek (someFILEpointer, 20, SEEK_SET) в файле с «abcdefg» в качестве содержимого?

Решение

POSIX позволяет искать за пределами существующего конца файла. Если вывод выполняется после этого поиска, любое чтение из промежутка вернет ноль байтов. Где поддерживается файловой системой, это создает разреженный файл.

Похоже, что он должен возвращать состояние без ошибок, но последующие чтения могут завершиться ошибкой. Последующие записи могут быть успешными, но точное поведение может зависеть от базовой файловой системы.

Другие решения

В Linux (и Unix в целом) он успешно завершится и вернет новое смещение, измеренное с начала файла, но размер файла не увеличится, пока вы не напишите что-либо с этим смещением.

Ваша неписанная часть будет считана из файла как нули, но в зависимости от ОС и файловой системы некоторые нули могут не занимать место на жестком диске.

Стандарт C оставляет его определяемым реализацией, является ли такой вызов fseek успешно или нет. Если положение файла не может быть установлено указанным способом, fseek вернет сообщение об ошибке.

Бинарный поток не нуждается в значительной поддержке fseek звонки со значением откуда SEEK_END , (§7.21.9.2 / 3)

Для текстового потока либо смещение должно быть равно нулю, либо смещение должно быть значением, возвращенным ранее успешным вызовом ftell функция в потоке, связанном с тем же файлом и откуда SEEK_SET ,

Таким образом, ни в том, ни в другом случае вам не гарантирован fseek с ненулевым смещением и откуда установлено SEEK_END ,

Posix разрешает звонок (цитаты из описание fseek ):

fseek() Функция должна позволять устанавливать индикатор положения файла за пределы конца существующих данных в файле. Если в этот момент данные записываются позже, последующие чтения данных в промежутке должны возвращать байты со значением 0, пока данные фактически не будут записаны в промежуток.

(Posix оставляет за собой право решать, хранятся ли байты со значением 0 на самом деле или являются неявными. Большинство файловых систем Unix реализуют разреженные файлы, которые могут оптимизировать этот случай, не сохраняя нули в постоянном хранилище, но это невозможно в Файловая система FAT, например.)

Даже Posix дает такую ​​гарантию только для обычных файлов:

Поведение fseek() на устройствах, которые не в состоянии искать, определяется реализацией. Значение смещения файла, связанного с таким устройством, не определено.

Таким образом, вызов может завершиться неудачно, но это не неопределенное поведение. Если перепозиционирование невозможно, fseek вернет ненулевое значение; в случае реализации Posix ненулевое значение будет -1 а также errno будет установлено значение, которое может помочь выяснить причину сбоя.

PHP: Функция fseek()

Покончив с основами чтения и записи текстовых файлов, давайте теперь уделим немного внимания работе с бинарными файлами. Работать с бинарными файлами намного труднее, чем с текстовыми, поскольку они по своей природе являются нечитабельными, и доступны для чтения только компьютеру.

В РНР запись бинарных файлов осуществляется так же, как и запись текстовых файлов (посредством функции fputs ()) и поэтому не требует дополнительных разъяснений. Фактически, единственным отличием (которое уже упоминалось) является использование режима b при открытии файла функцией fopen ().

Поэтому текущий раздел посвящен в основном функциям, связанным с чтением из файла бинарных данных и преобразованием их к виду, используемому в РНР. А именно, мы попробуем написать функцию, которая читает заголовок Zip-файла и определяет минимальный номер версии программы Zip, необходимой для распаковки этого файла. Для этого мы сначала ознакомимся с функциями fseek(),fread( ) и unpack().

При работе с бинарными файлами часто возникает необходимость перехода в различные позиции (или смещения) файла. Этим она отличается от работы с текстовыми файлами, которые, как правило, читаются и пишутся последовательно. В РНР установка указателя файла по определенному смещению внутри открытого файла осуществляется с помощью функции fseek (), которая имеет следующий синтаксис:

fseek($file ref, $offset [, $reference]) ;

где $file_ref — это поток, a $offset указывает число байт смещения от позиции, определяемой третьим параметром Sreference, который принимает значение одной из следующих трех констант.

Константы позиционирования для функции fseek()

SEEK_SET (По умолчанию) начало файла.
SEEK_CUR Текущая позиция файла.
SEEK END Байт, следующий за концом файла.

При использовании функции fseek() вполне допустимо устанавливать указатель файла за пределами файла. Хотя операция чтения из такой позиции завершится ошибкой, запись в эту позицию возможна и приведет к увеличению размера файла.

Функция fseek () возвращает нуль в случае успешного завершения и -1 в случае, если указатель файла не может быть установлен. Обратите внимание также на то, что отсчет смещений указателя в fseek() начинается с нуля и, следовательно, это необходимо учитывать при передаче параметра $of f set . Чтобы установить указатель файла в позицию $offset, функции fseek() необходимо передать параметр $offset — 1

FSEEK Попутно отрицательное смещение и SEEK_CUR

У меня есть плохая производительность работает fseek(..) в очень большой файл. Каждый раз , когда вызов fseek функции, мне нужно переместить позицию указателя файла в обратном направлении 100 bytes :

до того, что я делал это:

Мой вопрос заключается в том, как FSEEK перемещает указатель через файл и устанавливает указатель файла в определенном положении.

Я думал, что он принимает указатель на файл и перемещает его назад, но теперь я думаю, что это действительно является

получить текущую позицию ( cp )

добавить отрицательный индекс ( p = idx + cp )

и переместить указатель файла в начало файла в этой позиции ( fseek(fp, p, SEEK_SET) )

Во- первых, какая операционная система, которую вы используете? Если это Linux, запустить приложение под strace видеть , что система называет это на самом деле делает.

Во- вторых, fopen()/fseek()/fread() являются неправильные инструменты для этой модели доступа. Эти вызовы буфер файл читает — на чтение вперед . Это не делает вам никакой пользы. Вы fseek() компенсировать X, независимо от данных буферизованный теперь бесполезно, вы fread() 100 байт, а буферном fread() читает больше — вероятно , 8 кбайт. Вы , вероятно , читает почти каждый байт файла более чем в 80 раз. Вы можете использовать использовать setbuf() или setvbuf() отключить буферизацию, но тогда вы будете делать 100-байт читает, проходя через файл в обратном направлении. Это должно быть быстрее, но не так быстро , как вы можете идти.

Для того, чтобы сделать это так же быстро, как вы можете (не вдаваясь в многопоточный и / или асинхронный ввод-вывод):

Используйте open()/pread() . Вам не нужно искать — pread() читает непосредственно от произвольного смещения.

Читайте большие куски — скажем , 8192 х 100. Или даже больше. Читайте назад так же , как и раньше, но сделать буферные себя и начать со смещением в файле , который является кратным большого размера , которую вы читаете — первый для чтения, вероятно, будет меньше , чем 819,200 байт в нем. Процесс последние 100 байт в буфере, а затем работать в обратном направлении через буфер. Когда вы обработали первые 100 байт в буфере, используйте pread() для чтения предыдущих 819,200 байт (или даже больше) из файла.

Использование прямого ввода — вывода , если имеется. Файловая система оптимизации может попытаться «оптимизировать» ваш доступ на чтение вперед и размещения данных в кэше страниц — данные , которые вы уже обработаны. Поэтому обойти кэш страницы , если это возможно (не все операционные системы поддерживают прямой IO, а не все файловые системы на операционных системах , которые поддерживают прямой IO реализацию.)

Что-то вроде этого:

Вам нужно добавить обработку ошибок к этому.

На прикладном уровне пользователя, вы думаете о файле, как большой блок памяти и перемещении указателя файла как простая операция памяти (увеличение или уменьшение указателя, чтобы добраться до желаемого смещения в файле).

Но в библиотеке во время выполнения и на уровне ОС вещи совершенно разные. Код библиотеки времени выполнения, которая обрабатывает файлы не загружает все содержимое файла в памяти. Может быть, файл очень большой, может быть, вам только нужно прочитать только несколько байт из этого, есть много причин.

Библиотека времени выполнения (а также файловый кэш под управлением ОС) загружает только некоторые данные из файла в буфер памяти. Вы работаете с этими данными (читать, писать) и, если вы хотите получить доступ к информации, которая еще не загружен в буфере нагрузки коды управления файлами оно для вас; может быть, это увеличивает буфер или, может быть, он записывает буфер на файл (если он изменяется) или просто удаляет ранее загруженные данные (если он не был изменен) и загружает другой фрагмент данных в буфере.

При использовании fseek() для перехода к другой части файла , как правило , указатель файла поступает в области, которая не находится в памяти еще. Я полагаю , он загружает данные , начиная с нового положения указателя файла (на уровне операционной системы, кэш — файл загружает данные в нескольких дисковых блоков). Потому что вы бежите назад через файл я думаю , что данные в новой позиции указателя файла практически не загружен в память. Это вызывает доступ к диску , и это делает его медленным.

Я думаю , что лучшим решением для вас , чтобы использовать функции , предоставляемые операционной системой для отображения файла в память. Читайте о mmap() на Linux (и , возможно , на OSX) или сопоставления файлов в Windows. Это может помочь вам , но вполне возможно , что улучшение будет незначительным из-за определенный шаблон доступа вы используете. Большая часть времени программы чтения файла от начала до конца , и кода , который имеет дело с файлами и доступом к диску оптимизирован для этой модели.

fseek

fseek — Устанавливает смещение в файловом указателе

Описание

Устанавливает смещение в файле, на который ссылается handle . Новое смещение, измеряемое в байтах от начала файла, получается путём прибавления параметра offset к позиции, указанной в параметре whence , значения которого определяются следующим образом:

  • SEEK_SET — Устанавливает смещение в offset байт.
  • SEEK_CUR — Устанавливает смещение в текущее плюс offset .
  • SEEK_END — Устанавливает смещение в размер файла плюс offset . (Чтобы перейти к смещению перед концом файла, вы должны передать отрицательное значение в параметр offset .)

Если whence не указан, по умолчанию он устанавливается в SEEK_SET.

В случае успеха возвращает 0; в противном сучае возвращает -1. Обратите внимание, что переход к смещению за концом файла не считается ошибкой.

Пример #1 Пример использования функции fseek()

// читаем немного данных
$data = fgets ( $fp , 4096 );

// перемещаемся назад к началу файла
// то же самое, что и rewind($fp);
fseek ( $fp , 0 );

Не может использоваться на файловых указателях, возвращённых функцией fopen(), если они используют форматы «http://» или «ftp://». fseek() также возвращает неопределённый результат для потоков «дописать в конец» (открытых с флагом «a»).

Замечание: Параметр whence был добавлен в версии PHP 4.0.0.

См. также описание функций ftell() и rewind().

Коментарии

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.

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 ;
>
?>

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 ;

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

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.

function readlastline ( $file )
<
$linecontent = » » ;
$contents = file ( $file );
$linenumber = sizeof ( $file )- 1 ;
$linecontet = $contents [ $linenumber ];
unset( $contents , $linenumber );
return $linecontent ;
>
?>

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.

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.» ;
>
>

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.

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!

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.

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
//Seek to half way through
fseek($fp, $mid);

if($m > //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

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:

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 :/

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».

// 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.

easier tail() function for 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 ;
>
?>

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):

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

Modified @ben’s function to work for files larger than PHP_INT_MAX bytes.

function longTail ( $file , $numLines = 100 )
<
$fp = fopen ( $file , «r» );
$chunk = 4096 ;
$fs = sprintf ( «%u» , filesize ( $file ));
$max = ( intval ( $fs ) == PHP_INT_MAX ) ? PHP_INT_MAX : filesize ( $file );

for ( $len = 0 ; $len $max ; $len += $chunk ) <
$seekSize = ( $max — $len > $chunk ) ? $chunk : $max — $len ;

fseek ( $fp , ( $len + $seekSize ) * — 1 , SEEK_END );
$data = fread ( $fp , $seekSize ) . $data ;

if ( substr_count ( $data , «\n» ) >= $numLines + 1 ) <
preg_match ( «!(.*?\n)<" .( $numLines ). ">$!» , $data , $match );
fclose ( $fp );
return $match [ 0 ];
>
>
fclose ( $fp );
return $data ;
>
?>

This a tail php script example for windows system.

= ( isset( $_REQUEST [ ‘n’ ]) == true )? $_REQUEST [ ‘n’ ]: 20 ;

$offset = — $n * 120 ;

$rs = fopen ( ‘C:/wamp/logs/apache_error.log’ , ‘r’ );
if ( $rs === false )
die( «No se pudo abrir el archivo de log» );

fseek ( $rs , $offset , SEEK_END );

fgets ( $rs );
while(! feof ( $rs ))
<
$buffer = fgets ( $rs );
echo $buffer ;
echo » » ;
>

The official docs indicate that not all streams are seekable.
You can try to seek anyway and handle failure:

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

function fseekable ( $stream ) <
$meta = stream_get_meta_data ( $stream );
return $meta [ ‘seekable’ ];
>
?>

I needed to stream a txt file (here big xml file) to get nodes blockwise. I couldn’t find a shorter way. So i did write this class.

Function: streams a complete file and returns the content between two search strings with their search strings (multi byte safe)

Hope it helps anyone.

PS: It lacks any boolean checks / exception handling for non existing files / read errors.

/**
* Reads txt-files blockwise
* Usage:
$c_streamFileTxt = new streamFileTxt;
$_args = array(

‘file’ => ‘temporary.xml’,
‘start_string’ => ‘

while ($txt_block = $c_streamFileTxt->getNextBlock())
<
// use $txt_block for something
>
*/

class streamFileTxt
<
private $handle ;
private $file ;
private $file_offset ;
private $block ;
private $start_string ;
private $stop_string ;
private $block_size ;

/**
* Sett class arguments
* @param array $_args
*/
public function setArgs ( $_args )
<
$this -> file = $_args [ ‘file’ ];
$this -> start_string = $_args [ ‘start_string’ ];
$this -> stop_string = $_args [ ‘stop_string’ ];
$this -> block_size = $_args [ ‘block_size’ ];
>

/**
* Get next textblock within a file
* @param void
* @return string $textblock
*/
public function getNextBlock ()
<
$this -> openFile ();

fseek ( $this -> handle , $this -> file_offset );
$start_string_found = false ;
$stop_string_found = false ;
while (! feof ( $this -> handle ))
<
$txt_block = fread ( $this -> handle , $this -> block_size );

if (! $start_string_found ) // while not start start snippet found
<
$strpos = mb_strpos ( $txt_block , $this -> start_string );
if ( $strpos !== false )
<
// cut of first left chunk
$txt_block = mb_substr ( $txt_block , $strpos , $this -> block_size );
$start_string_found = true ;
>
>

if ( $start_string_found && ! $stop_string_found ) // start snipped found, looking for stop snippet
<
$strpos = mb_strpos ( $txt_block , $this -> stop_string );
if ( $strpos !== false )
<
$removed_block_size = mb_strlen ( $txt_block ) — $strpos ;
$txt_block = mb_substr ( $txt_block , 0 , $strpos + mb_strlen ( $this -> stop_string ));
$stop_string_found = true ;
$this -> setFileOffset ( $removed_block_size );
>
>

if ( $stop_string_found ) // stop-snippet found, keep file offset, return
<
$this -> closeFile ();
return $txt_block ;
>
>

$this -> closeFile ();
return false ;
>

/**
* Set current file offset and consider the removed block size
* current file position = current file offset — removed block size
* @param int $removed_block_size
*/
private function setFileOffset ( $removed_block_size )
<
$this -> file_offset = ftell ( $this -> handle ) — $removed_block_size ;
>

/**
* close current file
* @param void
* @return void
*/
private function openFile ()
<
$this -> handle = fopen ( $this -> file , ‘r’ );
>

/**
* open file
* @param void
* @return void
*/
private function closeFile ()
<
fclose ( $this -> handle );
>
>

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.

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

// 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

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

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

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

if ($char == «\n» || $char == «\r») <
++$totalLines;
> else <
$result[$totalLines] = $pos;
>
$pos++;

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

Fseek — Устанавливает смещение в файловом указателе

(PHP 3, PHP 4, PHP 5)

fseek — Устанавливает смещение в файловом указателе

Описание int fseek ( resource handle, int offset [, int whence] )

Устанавливает смещение в файле, на который ссылается handle . Новое смещение, измеряемое в байтах от начала файла, получается путём прибавления параметра offset к позиции, указанной в параметре whence , значения которого определяются следующим образом:

SEEK_SET — Устанавливает смещение в offset байт.
SEEK_CUR — Устанавливает смещение в текущее плюс offset .
SEEK_END — Устанавливает смещение в размер файла плюс offset . (Чтобы перейти к смещению перед концом файла, вы должны передать отрицательное значение в параметр offset .)

Если whence не указан, по умолчанию он устанавливается в SEEK_SET .

В случае успеха возвращает 0; в противном сучае возвращает -1. Обратите внимание, что переход к смещению за концом файла не считается ошибкой.

Пример 1. Пример использования функции fseek()

// читаем немного данных
$data = fgets ( $fp , 4096 );

// перемещаемся назад к началу файла
// то же самое, что и rewind($fp);
fseek ( $fp , 0 );

Замечание: Параметр whence был добавлен в версии PHP 4.0.0.

См. также описание функций ftell() и rewind() .

Пред. Начало След.
fscanf Уровень выше fstat

Если Вы не нашли что искали, то рекомендую воспользоваться поиском по сайту:

Илон Маск рекомендует:  Оформление гиперссылок, открывающих новое окно
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL