保存和堆栈溢出

发布于 2024-07-16 06:21:48 字数 1452 浏览 4 评论 0原文

我在 Delphi 中保存各种大型数据库类型时遇到问题。 它包含 TItem 的数组 [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;  

I'm having a problem saving a vary large database type in Delphi. It contains an array[1..3500] of TItem, which in turn has two arrays[1..50] and [1..20]. I get a stack overflow unless I set the variable as a Pointer and use the GetMem, FreeMem commands below, but then I can't save it. Code is below.

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;  

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

黯然#的苍凉 2024-07-23 06:21:48

使用 GetMem 或 SetLength 或 TList/TObjectList 并一次向文件写入一个 TSaveDB。 或者
更改文件类型并使用 BlockWrite 一次写入全部内容。 或者甚至更好:使用 TFileStream。

Use GetMem or SetLength or TList/TObjectList and write to the file one TSaveDB at a time. Or
change the file type and use BlockWrite to write it all at once. Or even better: use TFileStream.

维持三分热 2024-07-23 06:21:48

你的问题出在“write”语句中。 使用任意指针执行操作会导致各种奇怪的行为。 如果您使用 TFileStream 而不是当前的方法重写它,您会容易得多。

Your problem is in the "write" statement. Doing things with arbitrary pointers leads to all sorts of strange behavior. You'd have it a lot easier if you rewrote this using a TFileStream instead of the current approach.

半衾梦 2024-07-23 06:21:48

扩展梅森的答案:

永远读取或写入指针、句点。 想要从中得到任何合理的结果需要很大的运气,而在现实世界中,当你不只是再次运行你的程序时,成功的几率会从无限小到零。

相反,您需要读取和写入指针指向的内容。

另请注意,任何长度未在声明中指定的字符串都是指针,除非您在使“string”变为“string[255]”的兼容模式下运行——此模式的存在仅是为了与非常多的字符串兼容。当这是我们唯一的字符串时编写的旧代码。

由于您似乎只是将整个事情写出来,因此没有理由用固定大小的记录来玩游戏。 只需将每个字段写入流中,在写入字符串本身之前写入字符串的长度,以便您可以正确地将其加载回来。 文件会更小,并且不会被截断。

另外,正如他所说,使用 tFileStream。 旧格式用于保留在磁盘上的记录文件,在这种情况下没有理由使用它。

To expand on Mason's answer:

NEVER read or write a pointer, period. It would take a major stroke of luck to get anything reasonable out of doing it and in the real world when you're not just running your program again the odds of success go from infinitesimal to zero.

Rather, you need to read and write what the pointer points to.

Note, also, that any string whose length isn't named in the declaration is a pointer unless you're running in the compatibility mode that makes "string" into "string[255]"--this mode exists only for compatibility with very old code that was written when this was the only strings we had.

Since you appear to be simply writing the whole thing out there's no reason to be playing games with fixed size records. Simply write each field to a stream, write the length of a string before writing the string itself so you can load it back in properly. The file will be smaller and nothing gets truncated.

Also, as he says, use tFileStream. The old format has it's uses for a file of records that is left on disk, there's no reason to use it in a case like this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文