Сохранение и переполнение стека - PullRequest
0 голосов
/ 30 марта 2009

У меня проблема с сохранением большого размера базы данных в Delphi. Он содержит массив [1..3500] TItem, который в свою очередь имеет два массива [1..50] и [1..20]. Я получаю переполнение стека, если я не установлю переменную в качестве указателя и не воспользуюсь приведенными ниже командами GetMem, FreeMem, но потом не смогу ее сохранить. Код ниже.

procedure TDatabase.SaveDB;  
var  
 TempDB: ^TSaveDB;  
 K, X: integer;  
 sComment, sTitle, sComposer, sISDN, sCategory: string;  
begin  
GetMem(TempDB, SizeOf(TSaveDB));  

TempDB.CatCount := fCategoryCount;  
TempDB.ItemCount := fItemCount;  

for K := 1 to fCategoryCount do  
 TempDB.Categories[K] := fCategories[K];  

for K := 1 to fItemCount do  
 begin  
  fItems[K].ReturnSet(sTitle, sComposer, sCategory, sISDN, sComment);  
  with TempDB.Items[K] do  
   begin  
    Title := sTitle;  
    Composer := sComposer;  
    Category := sCategory;  
    ISDN := sISDN;  
   end;  

  TempDB.Items[K].Comments[1] := Copy(sComment, 1, 255);  
   Delete(sComment, 1, 255);  
  TempDB.Items[K].Comments[2] := Copy(sComment, 1, 255);  
   Delete(sComment, 1, 255);  
  TempDB.Items[K].Comments[3] := Copy(sComment, 1, 255);  
   Delete(sComment, 1, 255);  
  TempDB.Items[K].Comments[4] := Copy(sComment, 1, 255);  
   Delete(sComment, 1, 255);  

  TempDB.Items[K].KeyWCount := fItems[K].GetKeyCount;  

  for X := 1 to fItems[K].GetKeyCount do  
   TempDB.Items[K].Keywords[X] := fItems[K].GetKeywords(X);  
 end;

AssignFile(DBSave, fSaveName);  
 Rewrite(DBSave);  
  Write(DBSave, TempDB);  
Closefile(dBSave);  

FreeMem(TempDB, sizeof(TSaveDB));  
end;  

Ответы [ 3 ]

3 голосов
/ 30 марта 2009

Используйте GetMem или SetLength или TList / TObjectList и записывайте в файл по одной TSaveDB за раз. Или же измените тип файла и используйте BlockWrite, чтобы записать все сразу. Или еще лучше: используйте TFileStream.

1 голос
/ 31 марта 2009

Чтобы расширить ответ Мейсона:

НИКОГДА чтение или запись указателя, точка. Чтобы получить что-то разумное от этого, потребовалась бы большая удача, и в реальном мире, когда вы не просто снова запускаете свою программу, шансы на успех сводятся к бесконечно малому значению до нуля.

Скорее, вам нужно прочитать и написать то, на что указывает указатель.

Также обратите внимание, что любая строка, длина которой не указана в объявлении, является указателем, если вы не работаете в режиме совместимости, который превращает «строку» в «строку [255]» - этот режим существует только для совместимость с очень старым кодом, который был написан, когда это были единственные строки, которые у нас были.

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

Также, как он говорит, используйте tFileStream. В старом формате он используется для файла записей, оставленного на диске, поэтому нет причин использовать его в таком случае.

1 голос
/ 30 марта 2009

Ваша проблема в утверждении "написать". Работа с произвольными указателями приводит к всевозможному странному поведению. Вам было бы намного проще, если бы вы переписали это, используя TFileStream вместо текущего подхода.

...