Gzseek: примеры (PHP)

Функция gzseek для позиционирования в gzip-потоках
Раздел: Сжатие
gzseek(resource $stream, int $offset, int $whence = SEEK_SET): int

Функция gzseek устанавливает указатель позиции файла для gzip-ресурса. Она применяется для произвольного доступа к данным внутри сжатого файла, открытого с помощью gzopen(), что позволяет читать содержимое не с начала, а с определенного места.

Аргументы функции
  • stream (resource) - Указатель на gz-файл, который должен быть действительным и успешно открытым с помощью gzopen().
  • offset (int) - Смещение в байтах. В отличие от обычных файлов, смещение указывается в распакованных данных.
  • whence (int - необязательный) - Определяет точку отсчета для смещения. Принимает значения: SEEK_SET (по умолчанию - отсчет от начала файла), SEEK_CUR (от текущей позиции), SEEK_END (от конца файла). Добавлен в PHP 7.3.0.

Функция возвращает 0 в случае успеха, и -1 в случае неудачи. Для gzip-файлов, которые не поддерживают произвольный доступ (например, при чтении из стандартного ввода), функция всегда возвращает -1.

Простые примеры использования
Пример 1: Использование с SEEK_SET
<?php
$fp = gzopen('data.gz', 'r');
// Перемещаемся на 100-й байт распакованных данных от начала файла
$result = gzseek($fp, 100);
echo "Результат gzseek: $result\n"; // 0 - успех
// Читаем данные с новой позиции
echo gzread($fp, 20);
gzclose($fp);
?>
Результат gzseek: 0
[следующие 20 байт содержимого файла, начиная со 100-го]
Пример 2: Использование с SEEK_CUR (PHP >= 7.3)
<?php
$fp = gzopen('data.gz', 'r');
gzread($fp, 50); // Читаем 50 байт, позиция сдвигается
// Перемещаемся на 30 байт вперед от текущей позиции
$result = gzseek($fp, 30, SEEK_CUR);
echo "Результат: $result\n";
gzclose($fp);
?>
Результат: 0
Пример 3: Попытка некорректного позиционирования
<?php
$fp = gzopen('data.gz', 'r');
// Попытка перейти за пределы небольшого файла
$result = gzseek($fp, 1000000);
echo "Результат: $result\n"; // -1
// Указатель остается на прежней позиции (начало файла)
echo "Текущая позиция: " . gztell($fp) . "\n";
gzclose($fp);
?>
Результат: -1
Текущая позиция: 0
Похожие функции в PHP
  • gzrewind() - Сбрасывает указатель позиции в начало gz-файла. Удобна для повторного чтения файла с начала.
  • gztell() - Возвращает текущую позицию указателя чтения/записи в распакованных данных. Часто используется вместе с gzseek() для определения позиции.
  • fseek() - Аналогичная функция для работы с несжатыми файлами. Работает с обычными файловыми указателями, но не поддерживает gz-ресурсы.

Выбор функции зависит от задачи: gzseek() нужна для произвольного доступа внутри сжатого файла, gzrewind() - для быстрого возврата в начало, а gztell() - для диагностики текущего положения.

Аналоги в других языках
Python (модуль gzip)
import gzip
with gzip.open('data.gz', 'rb') as f:
    f.seek(100)  # Перемещение на 100-й байт распакованных данных
    data = f.read(20)
    print(data)
[байты со 100-го по 119-й]
JavaScript (Node.js, с использованием zlib и потоков)

Прямого аналога в чистом виде нет. Обычно требуется распаковать весь файл в память или буфер, затем использовать Buffer.slice() или позиционирование в потоке.

MySQL (компрессия на уровне протокола)

MySQL использует сжатие для передачи данных, но не предоставляет функций для позиционирования внутри сжатого потока на уровне запросов. Работа с архивами обычно происходит вне СУБД.

Типичные ошибки
Ошибка 1: Передача некорректного ресурса
<?php
$result = gzseek('not_a_resource', 10);
echo "Результат: $result\n";
?>
Warning: gzseek() expects parameter 1 to be resource, string given
Результат: (пусто или false в зависимости от конфигурации)
Ошибка 2: Использование с потоком, открытым только на запись
<?php
$fp = gzopen('output.gz', 'w');
$result = gzseek($fp, 10);
echo "Результат: $result\n"; // -1
gzclose($fp);
?>
Результат: -1
Ошибка 3: Некорректное использование whence в PHP < 7.3
<?php
// В PHP 7.2 и ниже
$fp = gzopen('data.gz', 'r');
$result = gzseek($fp, 10, SEEK_CUR); // Третий аргумент игнорируется
echo "Результат: $result\n";
gzclose($fp);
?>
Результат: 0 (смещение считается от начала файла, а не от текущей позиции)
Изменения в версиях PHP
  • PHP 7.3.0 - Добавлен необязательный третий аргумент whence. Это позволило использовать значения SEEK_SET, SEEK_CUR и SEEK_END для гибкого позиционирования, аналогично функции fseek().
  • До PHP 7.3 - Функция поддерживала только позиционирование от начала файла (SEEK_SET), а третий аргумент, если он передавался, игнорировался.
Расширенные примеры
Пример 1: Чтение файла с конца (PHP >= 7.3)
Пример php
<?php
$fp = gzopen('log.gz', 'r');
// Переход на 50 байт от конца распакованного файла
if (gzseek($fp, -50, SEEK_END) === 0) {
    echo "Последние 50 байт файла:\n";
    echo gzread($fp, 50);
} else {
    echo "Файл слишком мал для такого смещения.\n";
}
gzclose($fp);
?>
Последние 50 байт файла:
[содержимое последних 50 байт]
Пример 2: Построчное чтение с середины большого лог-файла
Пример php
<?php
// Ищем позицию, примерно соответствующую 75% файла
$fp = gzopen('huge_log.gz', 'r');
gzseek($fp, 0, SEEK_END);
$file_size = gztell($fp); // Узнаем размер распакованного файла
$target_pos = (int)($file_size * 0.75);
gzseek($fp, $target_pos);
// Пропускаем возможную "середину" строки
fgets($fp); // Читаем остаток строки, чтобы выровнять позицию на начало следующей строки
// Читаем следующие 10 строк
for ($i = 0; $i < 10; $i++) {
    $line = fgets($fp);
    if ($line === false) break;
    echo "Строка " . ($i+1) . ": $line";
}
gzclose($fp);
?>
Строка 1: [строка лога]
Строка 2: [строка лога]
...
Строка 10: [строка лога]
Пример 3: Создание индекса быстрого доступа к блокам данных
Пример php
<?php
// Предположим, что в файле хранятся блоки фиксированного размера (1000 байт)
// Создаем индекс: [номер_блока => позиция_в_файле]
$index = [];
$fp = gzopen('archive.gz', 'r');
$block_num = 0;
while (!gzeof($fp)) {
    $index[$block_num] = gztell($fp); // Запоминаем позицию начала блока
    // Пропускаем блок данных (читаем и игнорируем)
    gzread($fp, 1000);
    $block_num++;
}
// Теперь можно быстро прочитать любой блок по его номеру
$block_to_read = 42;
if (isset($index[$block_to_read])) {
    gzseek($fp, $index[$block_to_read]);
    $block_data = gzread($fp, 1000);
    echo "Содержимое блока $block_to_read: $block_data\n";
}
gzclose($fp);
?>
Содержимое блока 42: [данные блока]

PHP gzseek function comments

En
Gzseek Seek on a gz-file pointer