2.4.2. Работа с файлами¶
API работы с файлами обеспечивает передачу блобов между сервером и клиентом.
2.4.2.1. Блобы¶
В разделе затронуты темы сохранения, загрузки и передачи Blob-ов.
- Типичный порядок работы
- Выполнить запрос паскаль операции
- Параметр запроса сохранить в переменную выборки
- Переменную выборки сохранить на диск либо в поле выборки
- Используется также
- Открыть выборку с блоб-полем
- Сохранить поле на диск
- Порядок работы с большими данными
- Выполнить запрос паскаль операции
- В параметре запроса вернуть лоб-локатор
- Через лоб-локатор сохранить поток на диск
Note
- Под “Блоб”-ом понимается одна из трёх сущностей:
- тип sql-данных - Blob
- поле выборки куда выбрано поле типа Blob из sql-запроса
- переменная в скриптере где хранится массив байт
Во всех перечисленных случаях речь идёт о большом блоке данных.
Attention
Большинство методов напрямую работают с блобами и полностью копируют данные в память приложения. Из-за этого при больших объемах велика вероятность нехватки памяти. Решением проблемы работы с большими блобами/файлами является испопльзование лоб-локаторов.
2.4.2.1.1. Блоб в скриптере¶
Блоб в скриптере - обычная переменная, такая же как переменная хранящая число или строку.
Note
фактический тип данных Блоба в скриптере -
Variant array of Byte
. В описаниях методов чаще всего описывается простоVariant
, реже какArray
.Note
Блобы могут участвовать в работе с запросами и полями выборки, полностью аналогично значениям более простых типов (строки, числа..).
Тип данных БД который соответствует блобу в скриптере -
ftOraBlob
.Attention
Каждое присвоение Блоба в скрипотре, или передача не по ссылке, создаёт его копию и всего его содержимого. Если в переменной хранится значительный объём данных, то это чревато возникновением ошибки
Out of memory
See also
2.4.2.1.2. Блоб-поле¶
Работа с блоб-полем, как и с прочими блобами, сводится к загрузке и сохранению данных. Можно сразу работать непосредственно с файлами, или через “Блоб в скриптере”.
See also
- Прямые методы работы:
- Для работы с использование блобов в скриптере:
Attention
Лучше использовать методы прямой работы. Использовать “блобы в скриптере” при работе с блоб-полями не рекомендуется без необходимости. Этот подход потребляет значительно больше памяти.
Warning
При использовании обычных блобов (поля выборки) в SQL блоке, объявленных как [out] параметры, они имеют тип InputOutput. Если в такой блоб в SQL блоке присвоить знаение
NULL
, то после выполенния SQL блока может возникнуть ошибка “ORA-22922: nonexistent LOB value”. В таком случае, перед завершением SQL блока необходимо передать в блоб любое значение, кромеNULL
и пустой строки, и вызыватьDBMS_LOB.FREETEMPORARY(:лоб)
.
2.4.2.1.3. Примеры¶
<SQL> <GetBlob> [out blob] select bBlob into :blob from TSG_BlobExaple where id = :id; </GetBlob> </SQL> <PASCAL AFileName> V := ExecSQLEx('GetBlob', 'blob', [ftOraBlob], [Null]); SaveBlobToFile(AFileName, V[0]); </PASCAL><SQL> <SetBlob> update TSG_BlobExaple set bBlob = :blob where id = :id; </SetBlob> </SQL> <PASCAL AFileName> fileContent := LoadFromFileToBlob(AFileName); ExecSQLEx('SetBlob', 'blob', [ftOraBlob], [fileContent]); </PASCAL><SQL> <check> [out cpRes] begin if :bpIsPascal = 1 then :cpRes := btk_javapascalsqlparser.isCorrectSqlInPascal(:CLOBOPERATION); else :cpRes := btk_javapascalsqlparser.isCorrectPlSql(:CLOBOPERATION); end if; if :cpRes is null then :cpRes := ' '; dbms_lob.FreeTemporary(:cpRes); end if; end; </check> </SQL> <PASCAL> bvIsPascal := 0; v := execSqlEx('check', 'cpRes; bpIsPascal; CLOBOPERATION', [ftOraClob,ftFloat, ftOraClob], [null, bvIsPascal, null]); </PASCAL>
2.4.2.1.4. Лоб-локатор¶
Методика работы полностью аналогична работе с обычными параметрами типа
ftOraBlob
, но в качестве передаваемого значения используется не байтовый массив, а объект классаTbtkScriptOraLobLocator
, тип такого параметра следует задавать какftOraLobLocator
.Note
С помощью локаторов нельзя работать с полями выборки - только с параметрами запроса.
Note
Явным показанием к применению локатора является большой размер файла, тк. он не использует кеширование данных. Отправляет и принимает файл малыми порциями (потоково).
Note
Время жизни lob-локатора управляется ссылками, т.е. его можно передавать из операции в операцию и даже
AddVar
-ить. Но не стоит забывать о его связи с сессией: не следует использовать локатор созданный в одной сессии в запросах выполняемых в другой.Attention
При использовании обычных блобов (поля выборки) в SQL блоке, объявленных как [out] параметры, они имеют тип InputOutput. Но при использованиии
TbtkScriptOraLobLocator
в SQL блоке, обычные блобы, объявленные как [out] параметры, имеют тип Output.<SQL> <GetBlob> [out blob] select bBlob into :blob from TSG_BlobExaple where id = :id; </GetBlob> </SQL> <PASCAL AFileName> lob := Selection.CreateLobLocator; ExecSQLEx('GetBlob', 'lob', [ftOraLobLocator], [lob]); lob.SaveToFile(AFileName); </PASCAL><SQL> <SetBlob> update TSG_BlobExaple set bBlob = :blob where id = :id; </SetBlob> </SQL> <PASCAL AFileName> lob := Selection.CreateLobLocator; lob.CreateTemporary; lob.LoadFromFile(AFileName); ExecSQLEx('SetBlob', 'lob', [ftOraLobLocator], [lob]); </PASCAL>
2.4.2.2. Открытие документа¶
Запускается стороннее приложение ассоциированное с типом документа в системе. Под документом понимается файл на жёстком диске. Тип документа, как это принято в ОС Windows, соответствует расширению файла. Действие совершенно аналогично двойному клику по файлу ОС Windows.
2.4.2.2.1. Открытие файла с диска¶
Методы позволяют открывать документы или запускать на выполнение программы. Различаются возможностями печати и ожиданием закрытия файла (работа в модальном режиме).
See also
2.4.2.2.2. Открытие из поля выборки¶
Поле выборки должно быть типа Blob и содержать документ. Этот блоб сохраняется на диск и дальше происходит открытие файла с диска. Сохранение происходит во временный файл. После того как стороннее приложение будет закрыто
клиент Global
удалит этот временный файл.Note
При закрытии приложения Global, если какие-то из открытых документов ещё заняты (открыты в стороннем приложении) - выдаёт соответствующее предупреждение.
2.4.2.3. Диалоги¶
Диалоги навигации по файловой системе, такие как диалог открытия или сохранения файла, выбора каталога.
2.4.2.4. FAQ¶
- Каким методом узнать, что файл заблокирован?
Проверять файл на доступность перед открытием - плохое решение. Никто не сможет гарантировать, что между проверкой файла на доступность и его открытием не произойдет его блокировка. Оставлять такие случаи без рассмотрения - дурной тон и ненадежное программирование. Лучшим решением является обработка исключений от метода открытия файла. К сожалению, наш скриптер на данный момент не поддерживает полноценную структурную обработку исключений. Но кое-что придумать всё же можно:
ExecSQL( 'func' ); try Selection.BlobOpenEx2('blobe2', 'D:\Temp\foo.doc', Selection , '' ,wmAuto, true); except //ShowMessage(LastExceptionClassName); if SameText(LastExceptionClassName,'EFCreateError') then ShowMessage('Кажется что то пошло не так.'); end;
Если всё же очень хочется проверить файл на доступность заранее, то можно использовать следующий код:
<pascal> uses System; file_ := FileOpen('D:\31.log' ,fmOpenWrite); try If System.GetLastError <> 0 then ShowMessage(SysUtils.SysErrorMessage(System.GetLastError)); finally FileClose(file_); end; </pascal>