Как сохранить «массив записей» в TMemoryStream (чтобы затем сохранить его в поле BLOB sqlite)? - PullRequest
0 голосов
/ 14 марта 2011

В конечном счете, моя цель - сохранить структуру данных массива записей в поле BLOB sqlite, но пока я пытаюсь сериализовать массив записей и сохранить его в TMemoryStream.В случае, если это может быть уместно, я использую упаковщик sqlite Тима Андерсона (юникод) с Delphi 2010.

Это мой массив записей:

type
  TPerson = array of packed record
    sCountry: string[50];
    sFullName: string[100];
    sAddress: string[100];
    sCity: string[30];
    sEmployer: string[100];
  end;

var
  MyPeople       : TPerson;

А вот код, который я сейчас использую для сериализации этого массива записей в TMemoryStream.Проблема в том, что он не работает:

var
  i : integer;
  ms : TMemoryStream:
  ms2 : TMemoryStream;    
  TestPeople : TPerson;
  sldb              : TSQLiteDatabase;
begin
    ms := TMemoryStream.Create;
    ms2 := TMemoryStream.Create;
    sldb := TSQLiteDatabase.Create(slDBPath); //sldBPath is a global variable with path to sqlite db
    try
        i := Length(MyPeople);
        ms.Write(i, 4);
        ms.Write(pointer(MyPeople)^, i * sizeOf(MyPeople));
        ///
        ms2.Read(i, 4);  
        SetLength(ms2, i);
        ms2.Read(pointer(TestPeople)^, i * sizeOf(TestPeople));

        WriteLn('#############' + ms2[0].sFullName); //check if we can read data back

        sQuery := 'UPDATE PersonDirectory SET fldPersonBlob = ? WHERE id = "' + 42 + '";';
        sldb.UpdateBlob(sQuery, ms);

    finally
      ms.Free;
      ms2.Free;
      sqldb.Free;
    end;
end;

Любые идеи о том, как вообще сериализовать массив записей в TMemoryStream, или лучший способ хранения массива записей в поле BLOB sqlite

Ответы [ 3 ]

2 голосов
/ 14 марта 2011

Сделайте TPerson упакованной записью и объявите TPersons как массив TPerson.

type
  TPerson = packed record
    sCountry: string[50];
    sFullName: string[100];
    sAddress: string[100];
    sCity: string[30];
    sEmployer: string[100];
  end;
  TPersons = array of TPerson;
var
  MyPeople: TPersons;

Это позволяет вам получить SizeOf (TPerson), чтобы получить правильный размер записи, тогда как Length (MyPeople) будетдать вам длину массива.Умножьте их, чтобы получить общий размер байта.Это должно помочь вам начать.

Также обратите внимание, что некоторые действия чтения и записи начинаются с начала потока, в то время как другие продолжаются с текущего position.Иногда необходимо установить position в 0, прежде чем копировать содержимое потока в другой.В документации будет упомянуто это.

1 голос
/ 14 марта 2011

Вы можете использовать массив записей с простой строкой, а затем сохранить их в поток с помощью нашей обертки TDynArray.

Он будет использовать меньше места, чем короткие строки, потому что он будет писать только символы, используемые строкой. Например, sEmployer, определенный как строка [100], всегда будет использовать 101 байт при непосредственном сохранении. Принимая во внимание, что с нашим TDynArray, он будет использовать только число символов плюс один.

Работает с Delphi 6 до XE.

type
  TPerson = packed record
    sCountry: string;
    sFullName: string;
    sAddress: string;
    sCity: string;
    sEmployer: string;
  end;
  TPersons = array of TPerson;

var
  MyPeople: TPersons;

(...)
procedure SavePeopleToStream(Stream: TMemoryStream);
begin
  DynArray(TypeInfo(TPersons),MyPeople).SaveToStream(Stream);
end;

У вас есть обратный метод LoadFromStream и многое другое в TDynArray. Смотрите эту запись в блоге, чтобы получить эту оболочку .

Дополнительное примечание: Забавно, это та же самая функция Я собираюсь добавить к нашему ORM : хранить содержимое динамического массива в поле BLOB, закодированном в двоичном виде. Но в нашем случае все будет автоматизировано благодаря Delphi RTTI. Также существует уровень клиент / сервер, использующий JSON для передачи, чтобы сделать его более совместимым с n-Tier.

1 голос
/ 14 марта 2011

Возможно я ошибаюсь, но вы пишете в мс и читаете из мс2 .

ms2 - это поток памяти, но не указывает на то же содержимое памяти, на которое указывает ms . Я думаю, что ms2 не будет читать содержимое из ms , если вы не измените свой код.

Если вам нужно поместить содержимое мс в мс2 , попробуйте

ms2.LoadFromStream(ms);

до того, как вы начнете читать контент.

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

...