Pg lo tell: примеры (PHP)
pg_lo_tell(PgSql\Lob $lob): intФункция pg_lo_tell в PHP является частью модуля для работы с крупными объектами (Large Objects, LOB) в PostgreSQL. Она используется для определения текущей позиции чтения или записи внутри открытого крупного объекта.
Функция применяется при потоковой обработке данных крупных объектов, таких как изображения, документы или аудиофайлы, хранящиеся в базе данных PostgreSQL. Она позволяет узнать, на каком байте находится внутренний указатель объекта, что полезно для отслеживания прогресса операций, реализации механизмов возобновления передачи или контроля целостности данных.
Функция принимает один обязательный аргумент:
- $lob - ресурс (resource), представляющий открытый крупный объект. Этот ресурс должен быть получен с помощью функций
pg_lo_open()илиpg_lo_create().
Возвращаемое значение: целое число (int), указывающее текущее смещение (позицию в байтах) от начала объекта. В случае возникновения ошибки функция возвращает false.
Открываем крупный объект для записи, записываем строку и проверяем позицию.
<?php
$connection = pg_connect("dbname=test");
$lobId = pg_lo_create($connection); // Создаем новый объект
$handle = pg_lo_open($connection, $lobId, "w"); // Открываем для записи
$data = "Пример данных";
pg_lo_write($handle, $data); // Пишем данные
$position = pg_lo_tell($handle); // Получаем текущую позицию
echo "Позиция после записи: ".$position; // Должно быть равно длине строки
pg_lo_close($handle); // Закрываем объект
?>Позиция после записи: 25
Открываем существующий крупный объект для чтения, считываем часть данных и проверяем позицию.
<?php
$connection = pg_connect("dbname=test");
$lobId = 12345; // Существующий OID объекта
$handle = pg_lo_open($connection, $lobId, "r"); // Открываем для чтения
$chunk = pg_lo_read($handle, 10); // Читаем 10 байт
$position = pg_lo_tell($handle); // Получаем текущую позицию
echo "Прочитано 10 байт. Текущая позиция: ".$position;
pg_lo_close($handle);
?>Прочитано 10 байт. Текущая позиция: 10
- pg_lo_seek($lob, $offset, $whence = PGSQL_SEEK_CUR) - устанавливает позицию указателя в крупном объекте. Функция
pg_lo_tellчасто используется послеpg_lo_seekдля проверки нового положения. - pg_lo_read($lob, $length = 8192) - читает данные из объекта, автоматически перемещая указатель. Позицию после чтения можно проверить с помощью
pg_lo_tell. - pg_lo_write($lob, $data) - записывает данные в объект, также смещая указатель.
pg_lo_tellпомогает определить размер записанных данных. - filesize() и ftell() - аналоги для работы с обычными файлами в файловой системе.
pg_lo_tellвыполняет рольftell()для виртуальных файлов-объектов внутри PostgreSQL.
Функцию pg_lo_tell предпочтительно использовать именно при работе с крупными объектами PostgreSQL, в то время как ftell() применяется для стандартных файловых потоков.
В Python для работы с крупными объектами используется метод seek() и tell() у объекта LargeObject.
import psycopg2
conn = psycopg2.connect("dbname=test")
conn.autocommit = True
lob = conn.lobject(12345, 'rb') # Открытие объекта
lob.read(10)
position = lob.tell() # Получение позиции
print(f"Текущая позиция: {position}")
lob.close()Текущая позиция: 10
В Node.js прямой аналог может отсутствовать, так как работа с крупными объектами часто организуется через потоковое чтение/запись или SELECT-запросы к полям типа BYTEA/OID. Позицию можно отслеживать вручную через размер прочитанных чанков.
// Пример ручного отслеживания позиции при чтении
let position = 0;
const chunkSize = 1024;
// ... в цикле чтения
position += chunkSize;
console.log(`Текущая позиция: ${position}`);Pg lo tell в MySQL
В MySQL нет прямого аналога крупных объектов PostgreSQL. Для хранения больших данных используются типы BLOB, а для работы с ними данные обычно считываются или записываются целиком через запросы, что делает операцию "получить позицию" менее актуальной.
Функция ожидает корректный ресурс крупного объекта. Передача любого другого значения приведет к ошибке.
<?php
$connection = pg_connect("dbname=test");
$position = pg_lo_tell($connection); // Ошибка: $connection не ресурс объекта
echo $position;
?>Warning: pg_lo_tell() expects parameter 1 to be resource, resource given...
Попытка получить позицию после закрытия объекта приведет к ошибке.
<?php
$connection = pg_connect("dbname=test");
$handle = pg_lo_open($connection, 12345, "r");
pg_lo_close($handle);
$position = pg_lo_tell($handle); // Ресурс уже закрыт
?>Warning: pg_lo_tell(): supplied resource is not a valid large-object resource...
Функция работает с объектами, открытыми как для чтения, так и для записи. Однако если объект не был корректно открыт, возникнет ошибка.
Начиная с PHP 8.0, модуль PostgreSQL (pgsql) значительно обновлен. Функции для работы с крупными объектами, включая pg_lo_tell, теперь в случае ошибки выбрасывают исключения Exception, если не установлен обработчик ошибок.
В PHP 8.1 и 8.2 существенных изменений в поведении или сигнатуре функции pg_lo_tell не было. Рекомендуется использовать строгий режим типизации (declare(strict_types=1)) для избежания неявных преобразований типов аргументов.
Пример чтения большого объекта с выводом прогресса и возможностью возобновления с последней позиции.
<?php
declare(strict_types=1);
function readLargeObjectWithProgress($connection, int $lobId, int $startFrom = 0) {
$handle = pg_lo_open($connection, $lobId, "r");
if ($startFrom > 0) {
pg_lo_seek($handle, $startFrom, PGSQL_SEEK_SET);
}
$chunkSize = 8192;
$totalRead = $startFrom;
$savedPosition = $startFrom;
while (!feof($handle)) { // Условная проверка конца объекта
$data = pg_lo_read($handle, $chunkSize);
if ($data === false || $data === '') break;
$totalRead += strlen($data);
$currentPos = pg_lo_tell($handle); // Текущая позиция после чтения
echo "Прочитано: $currentPos байт\n";
// Пример условия для имитации сбоя и сохранения позиции
if ($totalRead > 50000) {
$savedPosition = $currentPos;
echo "Симуляция сбоя. Сохранена позиция: $savedPosition\n";
break;
}
}
pg_lo_close($handle);
return $savedPosition;
}
$conn = pg_connect("dbname=test");
$lastPosition = readLargeObjectWithProgress($conn, 12345, 0);
// При следующем запуске можно передать $lastPosition для возобновления
?>Прочитано: 8192 байт Прочитано: 16384 байт ... Симуляция сбоя. Сохранена позиция: 57344
Запись в объект из двух разных строк с проверкой промежуточных позиций.
<?php
$conn = pg_connect("dbname=test");
$lobId = pg_lo_create($conn);
$handle = pg_lo_open($conn, $lobId, "w");
$data1 = "Первая часть данных";
$data2 = "Вторая часть данных";
pg_lo_write($handle, $data1);
$pos1 = pg_lo_tell($handle);
echo "После первой записи: $pos1\n";
pg_lo_write($handle, $data2);
$pos2 = pg_lo_tell($handle);
echo "После второй записи: $pos2\n";
echo "Длина data2: ".($pos2 - $pos1)."\n";
pg_lo_close($handle);
?>После первой записи: 37 После второй записи: 74 Длина data2: 37