![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Передача битовой строки
Тормоз © (2002-09-12 08:02:00)Здравствуйте
Кто-нибудь знает как передать с сервера на клиент, ну например, картинку БМП. Вообще-то мне нужно передать сгенерированный отчет.
Пробовал передать в формате WideString - не получается, до клиента доходит всего 3 символа. Я так понимаю что передается только часть строки до #0
Подскажите, как быть.
Заранее спасибо
Олег Лаукарт (2002-10-07 10:18:00) [1]Относительно мороки с перекодированием в текст и т.д. Я использовал для передачи уже откатанный в системе механизм передачи справочников, которые представляют из себя XML документы. Не хотелось создавать новый механизм лишь для того, чтобы передавать бинарные шаблоны,так как они в моей ситуации были лишь одной из составляющих передаваемого информационного пакета. Поэтому пришлось пойти на удвоение объема с целью сокращения затрат на реализацию функциональности.
Если размеры передаваемых данных велики, частота отправки тоже большая и нет других ньюансов, то стоит использовать Any и т.п. Предложенный мною способ дан для расширения перечня возможных способов.
Удачи.
Набережных С. (2002-10-01 20:50:00) [2]
function GetVarArray(Data: Pointer; Len: integer):variant;
var
P:PInteger;
begin
Result:=VarArrayCreate([0,Len+SizeOf(Len)],varByte);
P:=VarArrayLock(Result);
P^:=Len;
Inc(P);
CopyMemory(P,Data,Len);
VarArrayUnlock(Result);
end;
function GetByteArray(const V: Variant; out Len: Integer):Pointer;
var
P:PInteger;
begin
P:=VarArrayLock(V);
Len:=P^;
GetMem(Result,Len);
Inc(P);
CopyMemory(Result,P,Len);
VarArrayUnlock(V);
end;
Пример:
var
v:variant;
procedure TForm1.Button3Click(Sender: TObject);
var
s:string;
begin
s:='Hello, Тормоз!'#0;
v:=GetVarArray(@s[1],Length(s));
end;
procedure TForm1.Button4Click(Sender: TObject);
var
P:PChar;
n:integer;
begin
Pointer(P):=GetByteArray(V,n);
v:=Unassigned;
ShowMessage(IntToStr(n));
ShowMessage(P);
FreeMem(P);
end;
P.S. Только добавь проверки, защищенные блоки и т.п.
Тормоз (2002-10-01 11:42:00) [3]А как можно передать массив?
Я если честно - чайник в таких технологиях, но сколько я читал статей, в них сказано, что массивы передаются в вариантах, которые сродни Any. Или я не прав?
KA_ (2002-10-01 10:08:00) [4]Вообще-то в моем случае используется тип any, что само по себе тормозит работу сиситемы. Если передаваемый файлы (или не файлы) все примерно одинакового размера, то можно вместо any использовать массив определив максимальный размер передаваемой информации. А при передаче обрезать его по длине outlen. Тогда по идее скорость должна возрости.
Тормоз (2002-10-01 05:51:00) [5]Здравствуйте.
Я сделал примерно как у KA_ - все работает довольно быстро.
По поводу способа Олега Лаукарта: я не понял, зачем затруднять себя передачей HEX-кодов. К тому же, для передачи одногобайта информации вы используете двабайта кодовой строки.
зы: Прошу прощения, если не то ляпнул
KA_ (2002-09-27 09:24:00) [6]Я передавал jpeg'и подобным образом:
У сервера:
function TIServ.GetFile(const filename : AnsiString;
out outdata : Any;
out outlen : Integer): Integer;
var
bytes: array of Byte;
begin
with TFileStream.Create(filename, fmOpenRead)do
begin
SetLength(bytes, Size);
Read(bytes[0], Size);
Free;
end;
outdata := bytes;
outlen := Length(bytes);
end;
У клиента:
var
bytes: array of Byte;
l: Integer;
v: variant;
...
begin
MyServer.Execute(anyfile, v, l);
SetLength(bytes, l);
bytes := v;
mstream := TMemoryStream.Create;
mstream.Write(bytes[0], l);
SetLength(bytes, 0);
mstream.Seek(soFromBeginning, 0);
jpg := TJPEGImage.Create;
jpg.LoadFromStream(mstream);
FreeAndNil(mstream);
bmp := TBitmap.Create;
bmp.Assign(jpg);
FreeAndNil(jpg);
bmp.SaveToFile(path + 'temp.bmp');
FreeAndNil(bmp);
...
end;
Файлы были по 4-6 мегов, по скорости передачи вопросов не было. Все происходит почти мгновенно. Но как видно из текста есть преобразование jpeg в bmp - требует уйму памяти и пр.
Олег Лаукарт (2002-09-25 10:24:00) [7]У меня была аналогичная задача. надо было передавать Excel-шаблоны. Вот какое решение я принял. конвертирую бинарный файл побайтно в последовательность символьных (hex) кодов. Т.е. строю текстовое представление. Оно правда в два раза больше оригинала, но ... с этим можно мириться. На клиенте расшифровую строку обратно в файл. вот код модуля.
const
HexChar : array[0..15] of WideChar=(
'0','1','2','3','4','5','6','7','8','9',
'A','B','C','D','E','F');
procedure LoadFileAsHEXString (FileName:string; var Str:WideString);
var
F : File of byte;
B : byte;
i : integer;
begin
AssignFile (F, FileName);
try
Reset (F);
SetLength (Str, FileSize (F)*2);
i := 1;
while not Eof (F) do begin
Read (F, B);
Str[i] := HexChar[B div 16];
Str[i+1] := HexChar[B mod 16];
inc (i, 2);
end;
finally CloseFile (F); end;
end;
procedure SaveHEXStringAsFile (Str:WideString; FileName:string);
var
F : File of byte;
B : byte;
i,j,j1,j2 : integer;
begin
AssignFile (F, FileName);
try
Rewrite (F);
i:=1;
while i<Length (Str) do begin
j1 := 0; j2 := 0;
for j:=0 to 15 do begin
if Str[i]=HexChar[j] then j1 := j;
if Str[i+1]=HexChar[j] then j2 := j;
end;
B := j1*16+j2;
Write (F, B);
inc (i,2);
end;
finally CloseFile (F); end;
end;
На практике проверено, что способ достаточно ефективен. файлы по 30К не вызывают видимых задержек.
Буду благодарен за коментарии.
msts (2002-09-12 15:40:00) [8]на чем написан сервер и клиент? -делфа?
как создаешь интерфейсы ? - idl? -> idl2pas?
тип "any" не подходит?
смотрим что генерит в частности idl2pas
------------------test1.idl-----------------------
module Test1 {
interface ITestStream {
long GetStream(in wstring Name);
};
};
----------------------
далее
function TITestStreamStub.GetStream ( const Name : WideString): Integer;
var
_Output: CORBA.OutputStream;
_Input : CORBA.InputStream;
_BitMap: TBitmap;
begin
inherited _CreateRequest('GetStream',True, _Output);
_Output.WriteWstring(Name);
inherited _Invoke(_Output, _Input);
_BitMap:= TBitmap.Create;
// _Input.ReadLong(Result); áûëî
_BitMap.LoadFromStream(_Input);
Result := integer(_BitMap);
end;
function TITestStream.GetStream ( const Name : WideString): Integer;
var
_BitMap: TBitmap;
begin
{ *************************** }
{ *** User code goes here *** }
{ *************************** }
Result := integer(_BitMap);
end;
procedure TITestStreamSkeleton._GetStream(const _Input: CORBA.InputStream; _Cookie: Pointer);
var
_Output : CORBA.OutputStream;
_Name : WideString;
_Result : Integer;
_BitMap: TBitmap;
begin
_Input.ReadWstring(_Name);
_Result := GetStream( _Name);
GetReplyBuffer(_Cookie, _Output);
// _Output.WriteLong(_Result);
_BitMap:= TBitmap(_Result)
_BitMap.SaveToStream(_Output);
end;
----------------
юзаем
TBitMap(ITestStream.GetStream('хахаха'))
ну а дальше варианты...
PS: применяйте фантазию, народ.
PS2: приведенный код не тестился, но идея ясна
Тормоз (2002-09-12 11:26:00) [9]Отчет в FastReport, я его формирую на севере и передаю на клиента. Из себя он представляет неперевариваемую информацию ~100k.
Сейчас я сделал так: побайтно заношу его в VariantArray, а на клиенте собираю обратно в одну строку типа string и дальше уже преобразовываю.
Так вот вопрос - существует ли более простой способ передачи двоичной информации (ну например из TMemoryStream)?
A. N. Onim (2002-09-12 10:04:00) [10]А ты давай в SAFEARRAY, а что за отчёт, если в XML, то лучше по HTTP.