I want to read blobfield (with blobstream) from client side (over network) but application freezes while fetching data. How can I read blobfield without freezing and showing percentage with a progressbar. (I'm using Delphi and Firebird)
i'm using uniquery component. i've found this code from: http://forums.devart.com/viewtopic.php?t=14629
but it doesn't work properly:
const
BlockSize= $F000;
var
Blob: TBlob;
Buffer: array of byte;
p: pointer;
pos, count: integer;
UniQuery1.SQL.Text:= 'select * from TABLE1 where FIELD_ID = 1';
UniQuery1.Open;
blob:= uniquery1.GetBlob('DATA');
SetLength(buffer, blob.Size);
ProgressBar1.Position:= 0;
Application.ProcessMessages;
repeat
count:= Blob.Read(pos, blocksize, p);
ProgressBar1.Position:= Round(pos/Blob.Size * 100);
pos:= pos + count;
p:= pointer(integer(p) + count);
Application.ProcessMessages;
until count < blocksize;
PS: i've set uniquery's options:
cacheblobs:= false;
streamedblobls:= true;
deferredblobread:= true;
in the first step of repeat-until loop, Blob.Read method reads all of stream, so it doesnt work properly.
You should use a thread, here is an example with Delphi
TThread
:So after applying this pattern to your code we get:
I removed the
Application.ProcessMessage
and moved all processing to the thread.The Thread is setting the
FPosition
private attribute and usesTThread.Synchronize
to set the ProgressBar position toFPosition
in the main thread.If your block size is not big enough this might still block the UI (due to excessive synchronization), so choose an appropriate block size or add some update delay.
You have to make sure that the connection of the
UniQuery1
object is not used in the main thread while the anonymous thread is running or move the connection and query to the thread as well.Also this can have reentrance problems, but it should give you a basic idea of how to use a thread for background processing.
PS: It might also be a good idea to run the query in the thread, especially if it can take some time.