Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2012.01.08;
Скачать: [xml.tar.bz2];

Вниз

Как работать с двухмерным динамический массивом?   Найти похожие ветки 

 
Очень Злой   (2011-09-29 18:11) [0]

Допустим, имеется такое:
type Trec=packed record
      Id:Cardinal;
      Cnt:packed array of cardinal;
      end;
...

var
  M:packed array of Trec;
...

Вот что-то запутался...
Если я буду менять размер массива M, то массивы M[n].Cnt будут сами создаваться и уничтожаться, или нужно это самому делать c помощью New и Dispose?


 
_Юрий   (2011-09-29 18:17) [1]

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


 
Очень Злой   (2011-09-29 18:31) [2]


> Это кстати никакой не двумерный динамический массив


Ну видимо я не силен в терминологии...

Есть еще вопрос: Эту массив нужно "запихнуть" в поток (чтобы сохранить в файл), ну и соответственно потом прочитать из файла...

Если я сделаю:
...
       lenArray:=length(M);
       WriteBuffer(lenarray,sizeof(lenarray));
       WriteBuffer(M[0],lenarray*sizeof(M[0]));
       // далее аналогично запинем все подмассивы
...

то потом читать так:
...
       ReadBuffer(lenarray,sizeof(lenarray));
       SetLength(M,lenarray);
       ReadBuffer(M[0],lenarray*sizeof(M[0]));
       // далее аналогично загружаем все подмассивы
...
будет нельзя?
Ведь по идее я запихну вместе с полезной информацией кучу ненужных указателей, которые при чтении будут неактуальны.
правильно?


 
Servy ©   (2011-09-29 18:58) [3]

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

Можно сделать для вашего TRec процедуру (в новых версиях Делфи можно добавить записи метод) для сериализации одной такой записи в поток. Ну и соответствующую процедуру для десериализации записи из потока. Внутри процедуры сериализации вполне можно записывать Cnt приведенным вами способом:

procedure SaveRecToStream(const Rec: TRec; DestStream: TStream);
var
 L: Integer;
begin
 with DestStream do
 begin
   WriteBuffer(Rec.Id, SizeOf(Rec.Id));
   L := Length(Rec.Cnt);
   WriteBuffer(L, SizeOf(L));
   WriteBuffer(Rec.Cnt[0], L * SizeOf(Rec.Cnt[0]));
 end;
end;

После чего, сохранение массива таких TRec"ов можно организовать, сохранив длину массива и по очереди все записи вышенаписанной процедурой. Загрузка тоже будет выглядеть весьма очевидной - читаем длину, устанавливаем размер массива записей, читаем все записи по очереди.


 
Очень Злой   (2011-09-29 19:31) [4]

Спасибо...
Переписал для моего конкретного случая, но на всякий случай спрошу:


uses ... zlib;
...
type TPassLine = packed array[1..8] of char;

type
 TUserData = packed record
   Uin:Cardinal;
   Nick:string[16];
   password:TPassLine;
   last_auth_time:TDateTime;
   FullName:string[50];
 end;

type
 TUser=packed record
    UserData:TUserData;
    Contacts: packed array of Cardinal;
 end;

type TUserList=packed array of TUser;

...

var
 UserList:TUserList;

...

procedure UsersDataSave(filename:string);
var
 fstream:TFileStream;
 LenArray:integer;
 LenSubArray:integer;
 i:integer;
begin
 fStream:=TFileStream.Create(filename,fmCreate);
 try
   with TCompressionStream.Create(clMax,fstream) do
     try
       lenArray:=length(UserList);
       WriteBuffer(lenarray,sizeof(lenarray));
       for i:=0 to lenarray-1 do
          begin
            WriteBuffer(UserList[i].UserData,sizeof(TUserdata));
            LenSubArray:=Length(UserList[i].Contacts);
            WriteBuffer(LenSubArray,sizeof(LenSubArray));
            WriteBuffer(UserList[i].Contacts[0],length(UserList[i].Contacts));
          end;
     finally
       Free;
     end;
 finally
   fstream.free;
 end;
end;


Сохранение так правильно?


 
Dennis I. Komarov ©   (2011-09-29 19:36) [5]

XML прям сам напрашивается...


 
Servy ©   (2011-09-29 19:41) [6]


> XML прям сам напрашивается...



> with TCompressionStream.Create(clMax,fstream) do


Человек тут за байты борется, а вы про текстовый Xml :).


> [4]



> WriteBuffer(UserList[i].Contacts[0],length(UserList[i].Contacts));

SizeoOf забыт. Я бы выделил таки в отдельную процедуру сериализацию элемента, иначе читается тяжеловато, и громоздкие конструкции типа UserList[i].Contacts[0] не очень вдохновляют. Но это уже эстетика.


 
Dennis I. Komarov ©   (2011-09-29 19:48) [7]


> Человек тут за байты борется, а вы про текстовый Xml :).

Я бы понял, если бы был трафик по сетке, но ведь файл


 
Очень злой   (2011-09-29 20:59) [8]


> Dennis I. Komarov ©   (29.09.11 19:36) [5]
>
> XML прям сам напрашивается...


Были мысли насчет XML, но не в плане сохранения в нем массива, а в плане вообще отказа от массивов и непосредственной работой с XML используя TXmlDoc, но потом решил, что это может внести лишние тормоза.
А если уж работать с массивами, то в сохранении массива в XML не вижу никакой выгоды, разве что на этапе отладки.
Кроме того,


> Человек тут за байты борется, а вы про текстовый Xml :).
>
>


Не то, чтобы борюсь, но не очень люблю, когда огромные файлы состоят большей частью из "воды"...


>  SizeoOf забыт.


Хм. действительно.


> Я бы выделил таки в отдельную процедуру сериализацию
> элемента, иначе читается тяжеловато, и громоздкие конструкции
> типа UserList[i].Contacts[0] не очень вдохновляют. Но это
>
> уже эстетика.


да вроде как процедура довольно небольшая по кол-ву строк, не думаю, что ее следует разбивать на несколько...


 
Ega23 ©   (2011-09-29 21:20) [9]


unit uMain;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls;

type

 TMyRecord = record
   ID: Cardinal;
   Cnt: array of Cardinal;
   procedure LoadFromStream(Stream: TStream);
   procedure SaveToStream(Stream: TStream);
 end;

 TForm10 = class(TForm)
   Button1: TButton;
   Memo1: TMemo;
   Button2: TButton;
   Edit1: TEdit;
   procedure Button1Click(Sender: TObject);
   procedure Button2Click(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form10: TForm10;

implementation

{$R *.dfm}

procedure TForm10.Button1Click(Sender: TObject);
var
 arr: array of TMyRecord;
 ms: TMemoryStream;
 i, j, arrLen: Integer;
begin
 arrLen := 5;
 SetLength(arr, arrLen);
 for i := 0 to arrLen - 1 do
 begin
   arr[i].ID := i + 1;
   SetLength(arr[i].Cnt, 5);
   for j := 0 to 4 do
     arr[i].Cnt[j] := j*100 + i;
 end;

 ms := TMemoryStream.Create;
 try
   ms.WriteBuffer(arrLen, SizeOf(Integer));
   for i := 0 to arrLen - 1 do
     arr[i].SaveToStream(ms);
   ms.SaveToFile(Edit1.Text);
 finally
   ms.Free;
 end;
end;

procedure TForm10.Button2Click(Sender: TObject);
var
 ms: TMemoryStream;
 i, j, arrLen, aCntLen: Integer;
 s: string;
 arr: array of TMyRecord;
begin
 ms := TMemoryStream.Create;
 try
   ms.LoadFromFile(Edit1.Text);
   ms.ReadBuffer(arrLen, SizeOf(Integer));
   SetLength(arr, arrLen);
   for i := 0 to arrLen - 1 do
     arr[i].LoadFromStream(ms);
 finally
   ms.Free;
 end;

 Memo1.Clear;

 for i := 0 to arrLen - 1 do
 begin
   aCntLen := Length(arr[i].Cnt);
   s := Format("ID = %d"#9"Cnt Count = %d"#9, [arr[i].ID, aCntLen]);
   if aCntLen > 0 then
   begin
     s := s + Format("Data: %d", [arr[i].Cnt[0]]);
     for j := 1 to aCntLen - 1 do
       s := s + Format(", %d", [arr[i].Cnt[j]]);
   end;
   Memo1.Lines.Add(s);

 end;

end;

{ TMyRecord }

procedure TMyRecord.LoadFromStream(Stream: TStream);
var
 i: Integer;
begin
 Stream.ReadBuffer(ID, SizeOf(Cardinal));
 Stream.ReadBuffer(i, SizeOf(Integer));
 SetLength(Cnt, i);
 Stream.ReadBuffer(Cnt[0], i * SizeOf(Cardinal));
end;

procedure TMyRecord.SaveToStream(Stream: TStream);
var
 i: Integer;
begin
 Stream.WriteBuffer(ID, SizeOf(Cardinal));
 i := Length(Cnt);
 Stream.WriteBuffer(i, SizeOf(Integer));
 Stream.WriteBuffer(Cnt[0], i * SizeOf(Cardinal));
end;

end.


 
Servy ©   (2011-09-29 21:35) [10]


> [9]

У топикстартера D7, методы к записям неподобавлять, что упоминалось в [3].

Кроме того, использование TMemoryStream вместо TFileStream для записи в файл вызывает некоторое недоумение. Чисто гипотетически, если у автора массив размером в гигабайт-полтора, то выделить еще столько же под MemoryStream для его сериализации может и не выйти. Понятно, что ситуация прямо скажем нечастая, но так как никакого профита от использования TMemoryStream не видно, то...


 
Servy ©   (2011-09-29 21:48) [11]


> А если уж работать с массивами, то в сохранении массива
> в XML не вижу никакой выгоды, разве что на этапе отладки.
>


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

Впрочем, xml не панацея, ибо во-первых производительность. Был бы нормальный способ бинарные данные в него пихать... А так, base64 какой-нибудь использовать приходится, что довольно печально. Во-вторых, возникающая дополнительная сложность, вместо задачи по сохранению массива вы получаете другую задачу - разбираться с xml парсерами, особенностями этого языка (типа всяких CDATA), заголовками, xslt и подобной ерундой, напрямую с решаемой задачей никак не связанной.

В общем, стоит взвесить все за и против.


 
Ega23 ©   (2011-09-29 22:37) [12]


>
> У топикстартера D7, методы к записям неподобавлять


Разве в семёрке нельзя?


> Кроме того, использование TMemoryStream вместо TFileStream
> для записи в файл вызывает некоторое недоумение.



procedure TCustomMemoryStream.SaveToFile(const FileName: string);
var
 Stream: TStream;
begin
 Stream := TFileStream.Create(FileName, fmCreate);
 try
   SaveToStream(Stream);
 finally
   Stream.Free;
 end;
end;


А поелику "ситуация прямо скажем нечастая", то профит есть и немалый, бо не надо на каждый WriteBuffer дёргать файловую операцию.


 
Ega23 ©   (2011-09-30 09:09) [13]

Не удержался вчера. Скачал и попытался установить D7 на Win7. Встало, но как-то криво. Хелп отказался запускаться, проект новый не создаётся, но новый юнит - можно. В юните по Ctrl+Shift+C на рекорде с методами ничего не произошло. Так что может быть действительно там методы в рекордах запрещены.
Но в таком случае сам Б-г велел сделать данные классом + класс-список.

TMyRecord = class (TObject)
public
 ID: Cardinal;
 Cnt: array of Cardinal;
 procedure LoadFromStream(Stream: TStream);
 procedure SaveToStream(Stream: TStream);
end;

TMyRecordList = class (TObjectList)
public
 property Items[Index: Integer]: TMyRecord read GetItem; default;
 procedure LoadFromStream(Stream: TStream);
 procedure SaveToStream(Stream: TStream);
end;


 
Очень Злой   (2011-09-30 09:58) [14]


> Но в таком случае сам Б-г велел сделать данные классом +
> класс-список.


Тоже неплохая мысль. Подумаю над этим...


 
Servy ©   (2011-09-30 22:55) [15]


> Но в таком случае сам Б-г велел сделать данные классом +
> класс-список.


Дык, с классами тогда можно от TPersistent унаследоваться, и published свойства автоматом сериализовать.


> Скачал и попытался установить D7 на Win7. Встало, но как-
> то криво.

У меня нормально работает под 64битной семеркой, если запускать с правами администратора. Хелп действительно не кажет, формат хелпа старый; можно конечно поставить какой-то костыль от майкрософта для его отображения, но мне проще пользоваться хелпом от более свежих версий.



Страницы: 1 вся ветка

Форум: "Начинающим";
Текущий архив: 2012.01.08;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.51 MB
Время: 0.003 c
2-1317454345
vgvolk
2011-10-01 11:32
2012.01.08
Разворачивание окна автоматически


15-1316925282
РВА
2011-09-25 08:34
2012.01.08
Подскажите по железу


15-1316809802
Юрий
2011-09-24 00:30
2012.01.08
С днем рождения ! 24 сентября 2011 суббота


6-1249301566
BreakPoint
2009-08-03 16:12
2012.01.08
Какой процесс слушает сокет?


2-1317359287
Natalie
2011-09-30 09:08
2012.01.08
Как отобразить в Memo тест длинною 4000 символов?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский