Преобразование TMemoryStream в вариант

Как преобразовать содержимое TMemoryStream в вариант? Я использую Делфи 2010.

TMemoryStream хранит содержимое файла, это может быть PDF или JPG (отсканированный документ).

Файл хранится в базе MS SQL. Когда я перехожу в режим редактирования в своей программе, я извлекаю содержимое этого файла из базы в TMemoryStream.

После редактирования карточки документа мне нужно отправить документ обратно в базу. Отсканированный файл также может быть изменен (или заменен каким-либо другим файлом). Чтобы отправить запись обратно, я использую хранимую процедуру с кучей параметров — по одному на каждое поле. Я передаю параметры хранимой процедуре как варианты.

Вот почему мне нужно преобразовать TMemoryStream в вариант.


person Vasiliy Volkov    schedule 16.01.2013    source источник
comment
Почему вы используете Variant для передачи данных в БД? Это не очень эффективно. Предполагая, что вы обернули хранимую процедуру внутри пользовательской функции, вы должны использовать фактические типы данных для каждого параметра или, по крайней мере, array of const, чтобы вы могли сохранить информацию о типе. В случае полей больших двоичных объектов вы можете опубликовать эти данные, используя TStream через TDataSet.CreateBlobStream() или TParam.AsStream.   -  person Remy Lebeau    schedule 16.01.2013
comment
Какой формат вы хотите использовать для хранения в варианте. Помните, что вариант — это просто контейнер.   -  person David Heffernan    schedule 16.01.2013
comment
Реми, спасибо за оба твоих поста. Я определенно должен превратить свои варианты обратно в реальные типы данных. Собственно, я сейчас не помню, почему я стал относиться к своим данным как к вариантам, так что пока у меня нет причин не вернуть все как было. Спасибо еще раз.   -  person Vasiliy Volkov    schedule 16.01.2013


Ответы (2)


Предполагая, что вам нужен Variant для хранения массива байтов, вы можете использовать это:

var
  MS: TMemoryStream;
  V: Variant;
  P: Pointer;
begin
  ...
  V := VarArrayCreate([0, MS.Size-1], varByte);
  if MS.Size > 0 then
  begin
    P := VarArrayLock(V);
    Move(MS.Memory^, P^, MS.Size);
    VarArrayUnlock(V);
  end;
  ...
end;
person Remy Lebeau    schedule 16.01.2013
comment
Что произойдет, если MS.size = 0 и вы в конечном итоге передадите -1 в качестве второго измерения VarArrayCreate? - person Mason Wheeler; 16.01.2013
comment
Это не проблема, потому что мы можем поставить if MS.Size > 0 на первое место. - person Vasiliy Volkov; 16.01.2013
comment
Установка верхней границы на -1 допустима. Так создаются пустые массивы. Количество элементов в массиве вычисляется как highbound - lowbound + 1, поэтому -1 - 0 + 1 равно 0. - person Remy Lebeau; 17.01.2013

TMemoryStream не имеет удобного способа получить прямой доступ к внутренним данным. Он предоставляет свойство, которое дает вам указатель, но не какой-либо полезный тип данных. Однако если вы используете TBytesStream, производное от TMemoryStream, вы можете получить данные из потока как переменную типа TBytes.

После этого, если ваш параметр является стандартным объектом параметра типа TParam, вам не нужно использовать вариант. Вы можете сделать это следующим образом:

param.AsBlob := MyTBytesVariable;

Или, что еще проще, вы можете использовать поток напрямую:

param.AsStream := MyMemoryStream;

(Если вы сделаете это, сначала убедитесь, что Position потока установлено в 0.)

person Mason Wheeler    schedule 16.01.2013
comment
TMemoryStream не имеет свойства, которое возвращает TBytes. Вы думаете о TBytesStream, которое происходит от TMemoryStream. - person Remy Lebeau; 17.01.2013