Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2003.09.15;
Скачать: CL | DM;

Вниз

Как правильно записать Blob в TStream в UDF ?   Найти похожие ветки 

 
Vorobyev Sergey   (2003-08-22 14:11) [0]

У меня есть следующий код (немного переделанный, в исходном варианте результат записывался не в TStream, а в PChar)

procedure BlobAsStream(Blob:TBlob; Stream:TMemoryStream);
var bytes_left, total_bytes_read, bytes_read:integer;
st:string;
begin
if (not Assigned(Blob.Handle)) then exit;
with Blob do
begin
bytes_left := TotalLength; // I have TotalSize bytes to read.
if (bytes_left = 0) then exit; // if I"ve nothing to copy, exit.
SetString(st, nil, TotalLength);
total_bytes_read := 0; // total bytes read is 0.
repeat
// Using BlobHandle, store at most "bytes_left" bytes in
// the buffer starting where I last left off
GetSegment(Handle, @st[total_bytes_read + 1], bytes_left, bytes_read);
// Increment total_bytes_read by the number of bytes actually read.
Inc(total_bytes_read, bytes_read);
// Decrement bytes_left by the number of bytes actually read.
Dec(bytes_left, bytes_read);
until bytes_left <= 0;
end;

Stream.Write(st[1], Blob.TotalLength);
end;


В результате получается такая БЯКА..
В строковой переменной st есть все данные до размера 16384, а дальше все нули.. Т.е. как будто бы все далее обрезается.. Почему?
Подскажите, пожалуйста..
Проверял под IB6, Yaffil.


 
Digitman ©   (2003-08-22 14:20) [1]

PMemoryStream = ^TMemoryStream;

...
function BlobToMemStream(Blob: PBlob): PMemoryStream; cdecl; export;
.....

function InternalGetBlob(Blob: PBlob; Buffer: Pointer; Size: Integer): ULong;
var
BytesRead: Integer;
begin
Result:= 0;
if Assigned(Blob) then with Blob^ do
if Assigned(BlobHandle) and Assigned(GetSegment) then
while (Size > 0) and Boolean(GetSegment(BlobHandle, PChar(Buffer) + Result, Size, BytesRead)) do begin
Inc(Result, BytesRead);
Dec(Size, BytesRead);
end;
end;

function BlobToMemStream(Blob: PBlob): PMemoryStream;
var
tmp: TMemoryStream;
begin
Result:= nil;
if Assigned(Blob) then
with Blob^ do
try
if Assigned(BlobHandle) and Assigned(GetSegment) then begin
tmp:= TMemoryStream.Create;
try
tmp.Size:= TotalSize;
InternalGetBlob(Blob, tmp.Memory, TotalSize);
Result:= PMemoryStream(Blob);
Result^:= tmp;
AttachedThreads.RegisterObject(Result^);
except
tmp.Free;
raise;
end;
end else
Result:= nil;
except
Result:= nil;
end;
end;


 
Vorobyev Sergey   (2003-08-22 14:37) [2]


> Digitman © (22.08.03 14:20) [1]

Проверил, все равно только первые 16384 байт берет, остальные обрезает..


 
Digitman ©   (2003-08-22 14:43) [3]

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


 
Digitman ©   (2003-08-22 14:44) [4]

покажи, как ры реализуешь обратную операцию : TStream -> Blob


 
Vorobyev Sergey   (2003-08-22 14:51) [5]


> покажи, как ры реализуешь обратную операцию : TStream ->
> Blob

не понял, зачем?


 
Digitman ©   (2003-08-22 14:54) [6]


> Vorobyev Sergey


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


 
Vorobyev Sergey   (2003-08-22 14:58) [7]

Содержимое блоб формируется другими модулями, там все нормально..

Полный размер блоба около 300кБ, там содержится просто текст..

Если считывать Blob в TStream в программе, например что-то типа
IBQuery1.FieldByName("BlobField").SaveToStream(Stream), то все считывается нормально..
потом идет анализ этого Stream и т.п.
Но чтобы не делать этого на клиенте, хочется реализовать на сервере, а в UDF никак не могу считать Blob в TStream..

Попробуй сам.
Запиши в блоб текст больше 16к.
Затем считай его в Stream своей процедурой в UDF и сохрани результат в файл ( Stream.SaveToFile)
Я так и проверял..


 
Verg ©   (2003-08-22 15:09) [8]

const segsize = 80;
....
Далее из Digitman

> while (Size > 0) and Boolean(GetSegment(BlobHandle, PChar(Buffer)
> + Result, min(Size, SegSize), BytesRead)) do begin


 
Vorobyev Sergey   (2003-08-22 15:11) [9]


> Verg © (22.08.03 15:09) [8]

Не понял, конечно, почему так, но проверил..
НЕ РАБОТАЕТ!!!


 
Verg ©   (2003-08-22 15:14) [10]

http://www.ibase.ru/d_udf.htm

файл udfdemo.zip

Глянь...


 
Verg ©   (2003-08-22 15:18) [11]

Да, кстати, перед каждым вызовом getSegment надо BytesRead:=0;


 
Vorobyev Sergey   (2003-08-22 15:34) [12]


> Verg © (22.08.03 15:14) [10]
> http://www.ibase.ru/d_udf.htm
>
> файл udfdemo.zip
>
> Глянь...

Это все я уже перелопатил давно..

Потом пробовал функции из FreeUDFLib и т.п.


> Verg © (22.08.03 15:18) [11]
> Да, кстати, перед каждым вызовом getSegment надо BytesRead:=0;


И так попробовал.. НЕ ВЫХОДИТ!!!

Попробую описать конкретней задачу:
Есть таблица в которой есть блоб-поле data, там записаны текстовые данные..

Запросом
select id, GetImportantWords(data) as text from table1 выбираю значения..
Где GetImportantWords - функция из UDF, которая анализирует блоб и вовращает эти ImportantWords..

Использую внутреннюю функцию (не экспортируемую) BlobAsStream для получения текста для дальнейшего анализа, так вот получается что есть только 16384 байт этого текста!!!
И соответственно эти ImportantWords берутся только из этого объема текста..


 
Digitman ©   (2003-08-22 15:38) [13]


> Verg


насчет Min() - да, здесь ты прав, это будет корректней

а насчет обнуления результирующего сч-ка перед GetSegment() - в этом нет никакого смысла


 
Verg ©   (2003-08-22 15:50) [14]

Я работаю под Fb1.5 RCx - никаких проблем с BLOB-ами.

> Digitman © (22.08.03 15:38) [13]


Вот оригинал:

function FillBuffer(var BLOb : TBLOb; Buf : PChar; FreeBufLen : Integer;
var ReadLen : Integer) : Boolean;
var
EndOfBLOb : Boolean;
FreeBufLenX, GotLength : Long;
begin
try
ReadLen := 0;
repeat
GotLength := 0; { !?! }
if FreeBufLen > MaxBLObPutLength then FreeBufLenX := MaxBLObPutLength
else FreeBufLenX := FreeBufLen;

with BLOb do
EndOfBLOb := not GetSegment(Handle, Buf + ReadLen, FreeBufLenX, GotLength);

Inc(ReadLen, GotLength);
Dec(FreeBufLen, GotLength);
until EndOfBLOb or (FreeBufLen = 0);
except
on E: Exception do begin
{$Ifdef Debug}
Writeln(X, E.Message);
Writeln(X, ReadLen, " ", FreeBufLen, " ", GotLength, " ", EndOfBLOb);
Flush(X);
{$Endif}
EndOfBLOb := True;
end;
end;
Buf[ReadLen] := #0;
Result := EndOfBLOb;
end;


Что-бы зничило { !?! }.
Я на всякий случай оставил.


 
Digitman ©   (2003-08-22 16:05) [15]


> Verg


это не оригинал)... это шаман-чукча с бубном писал !)

вот оригинал :

InterBase 6
Developer’s
Guide

blob_get_segment The first field in the Blob struct, blob_get_segment, is a pointer to a
function that is called to read a segment from a Blob if one is passed
to the UDF. The function takes four arguments: a Blob handle, the
address of a buffer into which to place Blob a segment of data that
is read, the size of that buffer, and the address of variable into to
store the size of the segment that is read
. If Blob data is not read by
the UDF, set blob_get_segment to NULL.


 
Digitman ©   (2003-08-22 16:36) [16]


> Vorobyev Sergey


не знаю я....

у меня все работает ....

только что сгонял туда-сюда 17000 байт текста - все в порядке : что записал, то и прочитал


 
Vorobyev Sergey   (2003-08-23 13:08) [17]

Ну хорошо... забудем про Stream-ы...
попробуйте в точности так, у меня (описано ниже)..
Если у вас пойдет, то я сдаюсь... :-(

1. Запишите в блоб текст, размером > 16384

2. в UDF опишите следующую функцию (без всяких TStream-ов):

...
function BlobAsPChar(Blob: PBlob): PChar; cdecl; export;
var
bytes_read, bytes_left, total_bytes_read: Long;
st: String;
begin
result := nil;
if (not Assigned(Blob)) or
(not Assigned(Blob^.BlobHandle)) then exit;
with Blob^ do
begin
bytes_left := TotalSize; // I have TotalSize bytes to read.
if (bytes_left = 0) then exit; // if I"ve nothing to copy, exit.
SetString(st, nil, TotalSize);
total_bytes_read := 0; // total bytes read is 0.
repeat
// Using BlobHandle, store at most "bytes_left" bytes in
// the buffer starting where I last left off
GetSegment(BlobHandle, @st[total_bytes_read + 1], bytes_left,
bytes_read);
// Increment total_bytes_read by the number of bytes actually read.
Inc(total_bytes_read, bytes_read);
// Decrement bytes_left by the number of bytes actually read.
Dec(bytes_left, bytes_read);
until bytes_left <= 0;
end;

Result := AllocMem(Length(st) + 1);
Result := StrLCopy(Result, PChar(st) + 16380 {!!!}, Length(st));
end;
...
exports
BlobAsPChar;


3. Описание функции в базе

DECLARE EXTERNAL FUNCTION GET_TEXT
BLOB
RETURNS CSTRING(20000) FREE_IT
ENTRY_POINT "BlobAsPChar" MODULE_NAME "test_udf.dll"


4. Запрос (выводит текст, начиная с 16380 символа в блоб)
select get_text(data) from table1

-------------------------------------------------------------

И ВОТ ГДЕ ЗДЕСЬ ОШИБКА ???


 
Verg ©   (2003-08-23 16:20) [18]


.....
bytes_read:=0; // Using BlobHandle, store at most "bytes_left" bytes in
// the buffer starting where I last left off
GetSegment(BlobHandle, @st[total_bytes_read + 1], Min(bytes_left,MaxSegLength),
bytes_read);
....


Мли-ин, ну сделай так уже..! Ну работает! А как у тебя - НЕ работает!
Ведь заставил же... проверить...

Кстати, покажи описание TBlob.


 
Verg ©   (2003-08-23 16:27) [19]

Кстати, без MIN на fb1.5 RC5 - вешается клиент, а сервер - 99% CPU Usage.
Без bytes_read:=0 - GetSegment читает из блоба кусок непредсказуемой длины.


 
Vorobyev Sergey   (2003-08-23 16:34) [20]


> Verg © (23.08.03 16:20) [18]

Заработало!!!!!! Verg, спасибо!!
Теперь буду разбираться, что же я делал раньше не так..
И почему же все-таки нужно bytes_read := 0 и Min(bytes_left,MaxSegLength)..
Пригодится в будущем..


 
Verg ©   (2003-08-23 16:40) [21]


> Min(bytes_left,MaxSegLength)..


Ну это-то понятно, ведь функция называется Get Segment.
А вот bytes_read := 0 - это "просто надо" :))
Давно было не помню, хотя разбирался когда-то....

> это шаман-чукча с бубном писал !)


:))))


 
Verg ©   (2003-08-23 17:03) [22]

Вот еще что из памяти всплыло - достаточно чтобы старшее слово (старшие 16 бит) в bytes_read на входе GetSegment было равно 0...
Теперь дальше....
Когда-то GetSegment описывался так:

function(BlobHandle: PInt;
Buffer: PChar;
BufferSize: ushort;
var ResultLength: ushort): Short; cdecl;
а теперь
так
GetSegment : function(Handle : Pointer; Buffer : PChar;
MaxLength : Long; var ReadLength : Long) : WordBool; cdecl;

... и к чему это ???


 
Verg ©   (2003-08-23 19:24) [23]

Ну я и баклан!!! :)))


> function(BlobHandle: PInt;
> Buffer: PChar;
> BufferSize: ushort;
> var ResultLength: ushort):
> Short; cdecl;


Вот же оно где!

Vorobyev Sergey

> bytes_read, bytes_left, total_bytes_read: Long;

НЕТ!

НАДО:

> bytes_read : ushort;
> bytes_left, total_bytes_read: Long;


Digitman

> var
> BytesRead: Integer;

НЕТ!

НАДО:

> var
> BytesRead: word;


Не, ну ржал минут 15-ать :)))

Старею, блин...



Страницы: 1 вся ветка

Текущий архив: 2003.09.15;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.024 c
1-48645
Skif
2003-09-03 05:19
2003.09.15
Пробег по компонентам


3-48433
dot
2003-08-25 10:15
2003.09.15
Как сделать фильтр по нескольким полям?


3-48434
Lenchik_Z
2003-08-25 06:54
2003.09.15
ADOQuery


14-48758
Dimka Kolbaskin
2003-08-26 10:12
2003.09.15
Масло


14-48690
porto
2003-08-25 17:05
2003.09.15
skachat delphi 6