Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 23.06.2016, 07:54   #1
mahatmaQL
Пользователь
 
Регистрация: 02.04.2014
Сообщений: 18
По умолчанию создание массива вариантов

Доброго дня!
Нужны помощь и совет при решении следующей задачи.

Есть массив данных, который описывается структурой: имя, тип переменной, длина, величина. Имя и тип переменной по сути коды, например, 0 - длина, 1 - высота и т.п.; 0 - byte, 1 - string; 2 - word и т.п.
Длина - размерность (если 1, то число; >1 массив).
Величина - значение переменной имя. Если длина = 1, то величина = значению (только для 4 байтовых типов), если длина >1, то величина = смещению в байтах, начиная с которого в файле содержится массив.

Задача считать параметр величина в один массив. Думал, что это можно сделать, создав массив вариантов, но пока без результатов.

Код:
TDatas = record
     FName: word;
     FType: word;
     FLength: longword;
     FOffset: longword;
  end;

  TData = array of TDatas;
  TValues = array of variant;

{
....
}

procedure GetValue(fname1: string; AData: TData; var AValue: TValues);
var
  i,size,ValType: integer;
  FS: TFileStream;
  NumBytes: byte;
begin
  if not FileExists(fname1) then exit;
// устанавливается размерность массива вариантов  
SetLength(AValue,High(AData)+1); 
  for i:=Low(AData) to High(AData) do
  begin
     // определяется массив какого типа должен быть создан
      case AData[i].FType of
        1: ValType:=varByte;
        2: ValType:=varString;
        3: ValType:=varWord;
        4: ValType:=varLongWord;
       12: ValType:=varDouble;
     else ValType:=varLongWord;
     end;
{здесь при отладке вижу, что создать массив желаемого типа не получилось: variant array of unknown вместо, допустим, variant array of word}
     AValue[i]:=VarArrayCreate([1,AData[i].FLength],ValType);

// если размерность 1, то присваиваем значение поля FOffset
     if AData[i].FLength=1 then AValue[i][1]:=AData[i].FOffset
// если >1 смещаемся и считываем массив
     else if  AData[i].FLength>1 then
     begin
        FS:=TFileStream.Create(fname1,fmOpenRead,fmShareDenyWrite);
        try
           FS.Seek(AData[i].FOffset,soFromBeginning);
           // нет уверенности, что получится определить сколько байт занимает переменная через SizeOf()
           size:=sizeof(AValue[i][1]);
// поэтому делаю это вручную
           case ValType of
              varByte, varString: NumBytes:=1;
              varWord: NumBytes:=2;
              varLongWord: NumBytes:=4;
              varDouble: NumBytes:=8;
              else NumBytes:=4;
           end;

{ если бы считывались данные в динамический массив, то работала бы
конструкция  FS.Read(Pointer(AValue[i])^, NumBytes*AData[i].FLength),
но с массивом вариантов так не получается, а как правильно не знаю}          
           FS.Read(AValue[i], NumBytes*AData[i].FLength);
        finally
           FreeAndNil(FS);
        end;
     end;
  end;
end;
mahatmaQL вне форума Ответить с цитированием
Старый 23.06.2016, 18:24   #2
WindWest
 
Регистрация: 01.07.2010
Сообщений: 8
По умолчанию

Тут замечательный пример... переработай под себя.
http://programmersforum.ru/showpost....7&postcount=14
WindWest вне форума Ответить с цитированием
Старый 26.06.2016, 17:40   #3
mahatmaQL
Пользователь
 
Регистрация: 02.04.2014
Сообщений: 18
По умолчанию

WindWest,
К сожалению я не обладаю глубокими знаниями в программировании, поэтому не понял, как указанный пример может мне помочь.


Свою задачу я смог реализовать самостоятельно. Непосредственно считать из потока в массив вариантов у меня не получилось. Здесь получись пойти 2 путями:
1. Считать данные в переменную заданного типа элемент массива (я это делал через нетипизированный файл и BlockRead()).
2. Считать данные в динамический массив заданного типа из потока, а потом с помощью DynArrayToVariant() конвертировать этот массив в вариант-массив. Привожу код этой реализации.

Пришлось создавать отдельный тип для каждого массива определенного типа. По другому не представляю, как можно было сделать. Пришлось также отказаться от использования VarAsType(), т.к. она не хотела выдавать true для variant array of double, хотя для других типов функция правильно работала. Также на корректно сработала DynArrayToVariant для конвертации динамического массива word, поэтому поэтому пришлось вариант массив для этого типа пришлось вводить поэлементно.

Если у кого-то будут соображения относительно решения задачи, буду рад выслушать.

Код:
type
  TMetas = record
     FName: word;
     FType: word;
     FLength: longword;
     FOffset: longword;
  end;
  TMeta = array of TMetas;
  TValues = array of variant;

procedure GetOffsets2(fname1: string; AMeta: TMeta; var AValue: TValues);
type
  TArByte = array of byte;
  TArWord = array of word;
  TArLongWord = array of longword;
  TArDouble = array of double;
var
  i,j,ValType: integer;
  FS: TFileStream;
  NumBytes: byte;
  ArByte: TArByte;
  ArWord: TArWord;
  ArLongWord: TArLongWord;
  ArDouble: TArDouble;
  ch: char;
  str1: string;
begin
  if not FileExists(fname1) then exit;
  i:=High(AMeta)+1;
  SetLength(AValue,i);
  for i:=Low(AMeta) to High(AMeta) do
  begin
     case AMeta[i].FType of
        1: begin NumBytes:=1; ValType:=varByte; end;
        2: begin NumBytes:=1; ValType:=varOleStr; end;
        3: begin NumBytes:=2; ValType:=varWord; end;
        4: begin NumBytes:=4; ValType:=varLongWord; end;
        12: begin NumBytes:=8; ValType:=varDouble; end;
        else begin NumBytes:=4; ValType:=varLongWord; end;
     end;

     AValue[i]:=VarArrayCreate([1,AMeta[i].FLength],ValType);

     if AMeta[i].FLength=1 then AValue[i][1]:=AMeta[i].FOffset
     else if  AMeta[i].FLength>1 then
     begin
        FS:=TFileStream.Create(fname1,fmOpenRead,fmShareDenyWrite);
        try
           FS.Seek(AMeta[i].FOffset,soFromBeginning);
           if ValType=varByte then
           begin
              SetLength(ArByte,AMeta[i].FLength);
              FS.Read(Pointer(ArByte)^, NumBytes*AMeta[i].FLength);
              DynArrayToVariant(AValue[i],ArByte,TypeInfo(TArByte));
              ArByte:=nil;
           end
           else if ValType=varOleStr then
           begin
              VarArrayRedim(AValue[i],1);
              str1:='';
              for j:=1 to AMeta[i].FLength do
              begin
                 FS.Read(ch, 1);
                 str1:=str1+ch;
              end;
              AValue[i][1]:=str1;
           end
           else if ValType=varWord then
           begin
              SetLength(ArWord,AMeta[i].FLength);
              FS.Read(Pointer(ArWord)^, NumBytes*AMeta[i].FLength);
              for j:=Low(ArWord) to High(ArWord) do
              AValue[i][j+1]:=ArWord[j];
              ArWord:=nil;
           end
           else if ValType=varDouble then
           begin
              SetLength(ArDouble,AMeta[i].FLength);
              FS.Read(Pointer(ArDouble)^, NumBytes*AMeta[i].FLength);
              DynArrayToVariant(AValue[i],ArDouble,TypeInfo(TArDouble));
              ArDouble:=nil;
           end
           else //if ValType=varLongWord then
           begin
              SetLength(ArLongWord,AMeta[i].FLength);
              FS.Read(Pointer(ArLongWord)^, NumBytes*AMeta[i].FLength);
              DynArrayToVariant(AValue[i],ArLongWord,TypeInfo(TArLongWord));
              ArLongWord:=nil;
           end;
        finally
           FreeAndNil(FS);
        end;
     end;
     // test
     {for j:=VarArrayLowBound(AValue[i],1) to VarArrayHighBound(AValue[i],1) do
     Form1.Memo1.Lines.Add(VarToStr(AValue[i][j]))};
  end;
end;
mahatmaQL вне форума Ответить с цитированием
Старый 26.06.2016, 22:41   #4
WindWest
 
Регистрация: 01.07.2010
Сообщений: 8
По умолчанию

А почему именно такая структура данных это условие или ваше видение решения?
Для каких практических целей данная программа?

Последний раз редактировалось WindWest; 26.06.2016 в 23:07.
WindWest вне форума Ответить с цитированием
Старый 27.06.2016, 00:15   #5
mahatmaQL
Пользователь
 
Регистрация: 02.04.2014
Сообщений: 18
По умолчанию

эта структура описывает данные в формате TIFF и GeoTIFF. А цель программы - считать данные, обработать и совершать различные манипуляции.
Базовая спецификация формата

Структура описывает тэг данных об изображении.
Поле FOffset содержит информацию об изображении, как разрешение, сжатие и др, которые представляются одним числом.
Но и есть другие данные, например, значение пикселя, географическая проекция и др., которые представляют массивы смещений и кол-во байтов для чтения.

Вот я и пытался значения этого поля считать в один массив, который содержит разные типы данных размерностью от 1 до N
mahatmaQL вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Создание массива Катя100 Помощь студентам 5 05.05.2013 15:50
Перебор вариантов из элементов массива Taranov Паскаль, Turbo Pascal, PascalABC.NET 2 20.04.2013 22:01
Создание массива ValentinBuruak Помощь студентам 6 07.09.2012 13:10
Создание массива А(10,7) Queit72ru Помощь студентам 5 30.11.2011 18:15
создание массива lg12 Помощь студентам 13 23.08.2009 15:13