Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Базы данных и репортинг > Запись Variant в TMemoryStream


Автор: Steel 14.12.2011, 22:33
Здравствуйте. 
Пытаюсь заделать инструмент для перевода результата запроса (TADOQuery) к любой таблице БД Access в бинарный файл. 

Идея была в следующем:
1. Пройти по массиву полей Fields первой записи и сохранить в поток размеры полей, их имена и типы.
2. Идти по записям и сбрасывать в поток значения полей в соответствии с их размером.

Столкнулся с проблемой на втором шаге. У меня есть значения полей типа Variant (Fields[n].Value) и есть размер данных значений (Fields[n].DataSize), но я не могу эти значения записать. Если пытаюсь писать Fields[n].DataSize байт из Fields[n].Value - в поток пишется некая чушь, а не значение поля.

Вопрос: Как мне добыть нужное мне кол-во байт из типа Variant?

Автор: Snowy 14.12.2011, 22:38
Сначала присвой значение из вариант в переменную другого типа. Например в integer/string/array.
И записывай уже его. Обратно аналогично.
Поведение варианта не фиксировано и зависит от ситуации. Для записи в бинарный вид это не годится.

Автор: Steel 14.12.2011, 23:30
Тогда получается что я должен знать структуру таблицы. А я хотел сделать вариант именно для любой структуры.
Получается нету способа представить значение переменной типа Variant как к примеру массив байт?

Автор: Snowy 15.12.2011, 02:09
Ваиант меняет своё поведение в зависимости от ситуации.
А бинарная запись таких вольностей физически не может иметь.
В бинарной записи должно быть строгое определение, что писать.
Можно, конечно, конкретизировать поведение на уровне сериализации, но это будет ещё сложнее.
Могу предложить приводить все данные к string и писать их, как string.

Автор: Steel 15.12.2011, 20:14
В общем при следующей реализации удалось свалить в бинарный файл таблицу с полями типа {DateTime, Single, Byte}

Код

var
  k   : Integer;
  FS  : TFileStream;
  Buf : array of Byte;
  Q   : TADOQuery;


Код

  k := Q.Fields[i].DataSize;

  SetLength(Buf, k);
  FillChar(Buf[0], k, 0);
  Q.Fields[i].GetData(Buf, False);

  FS.Write(Buf[0], k);

Автор: Steel 15.12.2011, 20:32
Также провел эксперимент над TVarData. 
1. Присваивал значение переменной какого-либо типа.
2. Присваивал ее переменной типа Variant
3. Обнулял первую переменную
4. Копировал из TVarData(пременная типа Variant).VBytes[6] в буфер кол-во байт, соотвествующие типу иходной переменной.
5. Копировал столько же байт из буфера в исходную переменную
6. Проверял результат

Издевался над переменными типов {Integer, Word, LongWord, Byte, Double, Single}
В итоге в исходную переменную вернулось исходное значение во всех случаях, кроме того когда иходная переменная была типа Single.
Это случилось из-за того что сам Variant после присвоения ему такой переменной почему то считает себя Double.
Как это победить я не нашел. 

Код

var
  Val  : Variant;
  j    : Integer;
  i    : Integer;
  w    : Word;
  lw   : LongWord;
  si   : SmallInt;
  b    : Byte;
  d    : Double;
  s    : Single;
  bu   : array of Byte;
  rs   : String;
begin
  i  := -57890;
  b  := 232;
  d  := 4001.2345;
  s  := -4445.234;
  w  := 455;
  lw := 231233;
  si := 12341;
//  s := d;

  // ----------------------------------------------------
  Val := Unassigned;
  Val := i;
  i   := 0;
  j   := SizeOf(i);

  SetLength(bu, j);
  FillChar(bu[0], j, 0);

  Move(TVarData(Val).VBytes[6], bu[0], j);
  Move(bu[0], i, j);

  rs := 'i = ' + FormatFloat('0.00000', i);

  // ----------------------------------------------------
  Val := Unassigned;
  Val := si;
  si   := 0;
  j   := SizeOf(si);

  SetLength(bu, j);
  FillChar(bu[0], j, 0);

  Move(TVarData(Val).VBytes[6], bu[0], j);
  Move(bu[0], si, j);

  rs := rs + #13 + 'si = ' + FormatFloat('0.00000', si);

  // ----------------------------------------------------
  Val := Unassigned;
  Val := w;
  w   := 0;
  j   := SizeOf(w);

  SetLength(bu, j);
  FillChar(bu[0], j, 0);

  Move(TVarData(Val).VBytes[6], bu[0], j);
  Move(bu[0], w, j);

  rs := rs + #13 + 'w = ' + FormatFloat('0.00000', w);

  // ----------------------------------------------------
  Val := Unassigned;
  Val := lw;
  lw  := 0;
  j   := SizeOf(lw);

  SetLength(bu, j);
  FillChar(bu[0], j, 0);

  Move(TVarData(Val).VBytes[6], bu[0], j);
  Move(bu[0], lw, j);

  rs := rs + #13 + 'lw = ' + FormatFloat('0.00000', lw);

  // ----------------------------------------------------
  Val := Unassigned;
  Val := b;
  b   := 0;
  j   := SizeOf(b);

  SetLength(bu, j);
  FillChar(bu[0], j, 0);

  Move(TVarData(Val).VBytes[6], bu[0], j);
  Move(bu[0], b, j);
  rs := rs + #13 + 'b = ' +FormatFloat('0.00000', b);

  // ----------------------------------------------------
  Val := Unassigned;
  Val := d;
  d   := 0;
  j   := SizeOf(d);

  SetLength(bu, j);
  FillChar(bu[0], j, 0);

  Move(TVarData(Val).VBytes[6], bu[0], j);
  Move(bu[0], d, j);
  rs := rs + #13 + 'd = ' +FormatFloat('0.00000', d);

  // ----------------------------------------------------
  Val := Unassigned;
  Val := s;
  s   := 0;
  j   := SizeOf(s);

  SetLength(bu, j);
  FillChar(bu[0], j, 0);

  Move(TVarData(Val).VBytes[6], bu[0], j);
  Move(bu[0], s, j);
  rs := rs + #13 + 's = ' +FormatFloat('0.00000', s);

  ShowMessage(rs);
end;


PS использовал Delphi 2007

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)