rewind()
Узнайте, как использовать функцию rewind() в PHP для сброса указателя файла в начало открытого файла, с синтаксисом, примерами и типичными ошибками.
Введение
Когда вы читаете файл в PHP, внутренний указатель файла отслеживает вашу текущую позицию. Каждое чтение перемещает указатель вперёд, поэтому после достижения конца файла дальнейшие операции чтения не возвращают ничего. Функция rewind() перемещает указатель обратно к байту 0 — самому началу — позволяя вам читать тот же файл снова без его закрытия и повторного открытия.
На этой странице объясняется, что делает rewind(), её синтаксис и возвращаемое значение, когда её использовать, типичные ошибки и запускаемые примеры, которые вы можете адаптировать.
Что такое указатель файла
Представьте указатель файла как курсор внутри открытого файла. Такие функции, как fread(), fgets() и fgetcsv(), читают с позиции курсора, а затем перемещают его вперёд на количество прочитанных байтов. Вы можете проверить текущую позицию курсора с помощью ftell() и переместить его в произвольную позицию с помощью fseek().
rewind($handle) — это удобное сокращение для «вернуться в начало»; оно эквивалентно fseek($handle, 0).
Синтаксис
rewind(resource $handle): bool$handle— ресурс-указатель на файл, который ещё открыт; как правило, возвращается функциейfopen(). Он должен указывать на поток, допускающий позиционирование.- Возвращает
trueв случае успеха иfalseв случае ошибки.
Когда и зачем использовать
Используйте rewind() всякий раз, когда нужно прочитать или обработать один и тот же открытый файл более одного раза за время выполнения скрипта:
- Подсчёт, затем обработка. Первый проход для подсчёта строк или валидации, второй — для выполнения основной работы.
- Чтение после записи. После записи в файл, открытый в режиме чтения/записи (
'w+','r+','a+'), перемотайте перед тем, как читать записанное. - Потоки в памяти. Когда вы формируете содержимое в потоке
php://memoryилиphp://temp, перемотайте перед его чтением.
Если вы читаете файл только один раз, rewind() вам не нужна.
Примеры
Пример 1: Чтение одного файла дважды
В этом примере создаётся временный файл, который читается до конца, затем перематывается и читается снова.
<?php
// Create a temporary file we can read and write.
$handle = tmpfile();
fwrite($handle, "line one\nline two\n");
// Move to the start so we can read what we just wrote.
rewind($handle);
echo "First read:\n";
echo fread($handle, 1024);
// The pointer is now at the end; reading again gives nothing.
echo "After first read, position: " . ftell($handle) . "\n";
// Rewind and read the whole file again.
rewind($handle);
echo "Second read:\n";
echo fread($handle, 1024);
fclose($handle);Результат:
First read:
line one
line two
After first read, position: 18
Second read:
line one
line twoПервый вызов fread() оставляет указатель на байте 18 (конец файла). Без rewind() второе чтение вернуло бы пустую строку. После перемотки указатель возвращается на 0, и полное содержимое становится доступным снова.
Пример 2: Запись, перемотка и последующее чтение
Когда поток открыт и для записи, и для чтения, rewind() позволяет проверить записанное.
<?php
// php://memory is an in-memory read/write stream.
$handle = fopen('php://memory', 'r+');
fwrite($handle, 'Hello, W3Docs!');
// Without rewind, the pointer sits after the written text,
// so reading now would return an empty string.
rewind($handle);
$content = stream_get_contents($handle);
echo $content; // Hello, W3Docs!
fclose($handle);Результат:
Hello, W3Docs!Пример 3: Всегда проверяйте возвращаемое значение
rewind() возвращает false, если поток не поддерживает позиционирование (например, несекьюрный сетевой поток или канал).
<?php
$handle = fopen('php://memory', 'r+');
fwrite($handle, 'data');
if (rewind($handle)) {
echo "Pointer reset. Position: " . ftell($handle) . "\n";
} else {
echo "This stream cannot be rewound.\n";
}
fclose($handle);Результат:
Pointer reset. Position: 0Типичные ошибки
- Указатель уже находится в конце после чтения. Именно для этого и существует
rewind(). Если второе чтение не возвращает ничего, скорее всего, вы забыли перемотать. - Режим добавления (
'a'/'a+'). Перемотка перемещает указатель чтения в начало, но в режиме добавления каждый вызовfwrite()всё равно записывает в конец файла, независимо от позиции указателя. - Непозиционируемые потоки. Каналы, сокеты и некоторые HTTP-потоки нельзя перемотать;
rewind()вернётfalse. Проверяйте возвращаемое значение, если источник может не поддерживать позиционирование. - Закрытые дескрипторы. Вызов
rewind()для дескриптора, уже переданного вfclose(), вызовет предупреждение. Перематывайте до закрытия.
Связанные функции
fseek()— перемещает указатель на любое смещение в байтах (rewind()эквивалентнаfseek($handle, 0)).ftell()— возвращает текущую позицию указателя.fopen()— открывает файл или поток и возвращает дескриптор.fread()/fgets()— читают с текущей позиции.fclose()— закрывает дескриптор по завершении работы.
Заключение
rewind() сбрасывает внутренний указатель открытого файла в начало, позволяя повторно читать или обрабатывать данные в рамках одного запуска скрипта. Это тонкая удобная обёртка вокруг fseek($handle, 0). Не забывайте проверять возвращаемое значение для непозиционируемых потоков, учитывайте поведение режима добавления и перематывайте до закрытия дескриптора.