Сохранить TList в поток TMemoryStream и восстановить обратно

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Сохранить TList в поток TMemoryStream и восстановить обратно

Сообщение Nik » 14.05.2011 23:05:12

Продублирую вопрос из этой ветки в общем разделе.

Требуется сохранить массив указателей TList в поток TMemoryStream. Указатели разного типа (строки, int, doube), а потом передать на другой комп (это не проблема) и восстановить точную копию исходного TList.

Я пробовал в лоб:

Код: Выделить всё
fResults: TList;
...
res: TMemoryStream;
...

res.Write(fResults[i]^, SizeOf(fResults[i]));


Но при таком раскладе в потоке оказывается ерунда (что предсказуемо). Если писать fResults[i] - в поток попадают (если я правильно понял) адреса.

Кто-нибудь знает, как корректно записать Pointer неизвестного типа в поток и потом их обратно считать? Возможно ли это в принципе силами FPC/Lazarus?
Аватара пользователя
Nik
энтузиаст
 
Сообщения: 573
Зарегистрирован: 04.02.2006 00:08:09
Откуда: Киров

Re: Сохранить TList в поток TMemoryStream и восстановить обратно

Сообщение zub » 15.05.2011 01:03:53

В смысле записать и восстановить указатель? указатель он на то и указатель, что уже в следующей сессии будет пальцем в небо, не говоря уже о x32\x64
Код: Выделить всё
res.Write(fResults[i]^, SizeOf(fResults[i]));

пишете первые 4\8 байт от того на что ссылается fResults[i]^
Если указатель ссылается на чтото неизвестного типа - это никак не сохранить (хотя если вы с этим работаете, значит тип знаете), тип надо знать и писать вместе с содержимым, чтоб потом однозначно восстановить
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Сохранить TList в поток TMemoryStream и восстановить обратно

Сообщение Nik » 15.05.2011 11:52:28

Я пытаюсь сохранить данные по указателю (fResults[i]^). Тип, теоретически, я знаю (их всего 4, все вполне конкретные - строки, числа). Но как определить тип конкретного указателя - понять пока не могу (в массиве они перемешаны, всё зависит от типа данных в базе данных, которая лежит в конкретном TList).
Аватара пользователя
Nik
энтузиаст
 
Сообщения: 573
Зарегистрирован: 04.02.2006 00:08:09
Откуда: Киров

Re: Сохранить TList в поток TMemoryStream и восстановить обратно

Сообщение Max Rusov » 15.05.2011 12:52:25

Если Вы не знаете тип - задача не имеет смысла. Такие данные не только в поток нельзя записать, Вы их и локально никак не сможете обработать. Т.ч. - ищите доступ к типам.
Max Rusov
постоялец
 
Сообщения: 191
Зарегистрирован: 25.04.2009 15:46:03

Re: Сохранить TList в поток TMemoryStream и восстановить обратно

Сообщение hinst » 15.05.2011 13:13:00

Но как определить тип конкретного указателя - понять пока не могу

нельзя! более того, вы не только на другой комп не сможете их перекачать, но и на своём компе использовать!
или сможете? если да, то мне интересно, как...

я, между прочим, когда пытался замутить свою библиотеку компонентов для паскаля, делал такой список, чтобы он хранил все стандартные типы данных. Она, вроде бы, до сих пор висит на этом сайте. вот и ссылка на доку: http://epcl.wikispaces.com/EPCL.exVariantList. Вдруг вам понравится
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Re: Сохранить TList в поток TMemoryStream и восстановить обратно

Сообщение Odyssey » 15.05.2011 13:30:43

Определить тип по одному только указателю на значение нельзя. Тип и размер придётся где-то хранить явно.

Теоретически, вместо строк и чисел можно было бы использовать указатель на Variant (PVariant), или указатель на запись с полем типа и указателем на реальные данные.

В данном конкретном случае, поскольку требуется сохранение чужих структур, которые менять не желательно, нужно отдельно сохранять типы значений, которые в TSQLiteTable храняться в поле fColTypes. При этом и в момент записи поля в поток, и в момент чтения его из потока нужно проверять тип, так же как это делается в коде библиотеки:
Код: Выделить всё
if pInteger(fColTypes[i])^ = dtInt then
// и т.д.

В целом алгоритм будет примерно таким:
1) Пишем в поток число элементов fColTypes.
2) В цикле пишем все значения элементов fColTypes (они - pInteger, т.е. в поток должно записаться разыменованное значение указателя, которое будет типа Integer).
3) Пишем число элементов fResults.
4) В цикле пишем сами элементы fResults, каждый элемент в зависимости от типа. С числами всё просто: они Int64 при dtInt или Double при dtNumeric, достаточно разыменовать и записать полученные значения в поток. Строки нужно писать либо через TStream.WriteAnsiString, либо руками, подсмотрев реализацию этого метода. С блобами ещё чуть сложнее, нужно будет разыменовать указатель в TMemoryStream и скопировать его содержимое в наш Stream через TStream.CopyFrom.

Чтение - соответственно.

P.S.
Если непонятно, как определяется тип - см. destructor TSQLiteTable.Destroy:
Код: Выделить всё
iColNo := (i mod fColCount);
case pInteger(self.fColTypes[iColNo])^ of
  dtBlob: // ...
  dtStr: // ...
// ...
Odyssey
энтузиаст
 
Сообщения: 580
Зарегистрирован: 29.11.2007 17:32:24


Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 59

Рейтинг@Mail.ru