将打包记录数组保存到磁盘

时间:2018-01-09 10:30:04

标签: arrays delphi records tfilestream

我疯了。 我正在尝试将打包记录的数组保存到磁盘中以便以后读取。

以下单元主要包含两个程序。

  1. 第一个 InitSaveAndReLoad(),初始化一个打包的记录数组,将其保存到磁盘并从磁盘重新加载一个新的打包记录数组并通过加载的数组并打印出来20第一个值。效果很好。
  2. 第二个LoadFromFile(),只是从磁盘重新加载数组。它甚至可以通过InitSaveAndReload()调用,并且只要先前由相同的应用程序实例创建了文件,就能完美地工作。我的意思是如果我退出应用程序并重新启动,只是重新加载记录数组中的文件的LoadFromFile()过程不再起作用。我不明白为什么。
  3. 有任何线索吗?

    感谢您的帮助。已经花了一整天的时间来解决这个问题而变得疯狂!

    unit Unit4;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.DateUtils,
      System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Menus, Vcl.StdCtrls;
    
    type
      TRate = packed record
        time        : int64;
        open        : double;
        low         : double;
        high        : double;
        close       : double;
        tick_volume : int64;
        spread      : integer;
        real_volume : int64;
      end;
    
      PRate = ^TRate;
    
      TForm4 = class(TForm)
        MemoLogs: TMemo;
        SaveDialog1: TSaveDialog;
        edFile: TEdit;
        Button1: TButton;
        Button2: TButton;
        Button3: TButton;
        Button4: TButton;
        procedure InitSaveAndReload(Sender: TObject);
        procedure Reload(Sender: TObject);
        procedure SelectFile(Sender: TObject);
        procedure LoadFromFile();
        procedure Button4Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form4: TForm4;
    
    implementation
    
    {$R *.dfm}
    
    function TimeElapsedToString(time : int64; show_ms : boolean = false) : string;
    var
      TmpVal:real;
      TmpStr:string;
    begin
      TmpVal := time;
      TmpStr := '';
    
      TmpVal := TmpVal / 3600000;
      TmpStr := inttostr(trunc(TmpVal));
      if Length(TmpStr) = 1 then TmpStr := '0' + TmpStr;
    
    
      TmpVal := (TmpVal-trunc(TmpVal))* 3600000;
      TmpVal := TmpVal / 60000;
      if TmpVal<10 then
         TmpStr := TmpStr + ':0' + inttostr(trunc(TmpVal))
      else
         TmpStr := TmpStr + ':' + inttostr(trunc(TmpVal));
    
      TmpVal := (TmpVal-trunc(TmpVal))*60000;
      TmpVal := TmpVal / 1000;
      if TmpVal<10 then
         TmpStr := TmpStr + ':0' + inttostr(trunc(TmpVal))
      else
         TmpStr := TmpStr + ':' + inttostr(trunc(TmpVal));
    
      if show_ms then
      begin
        TmpVal := (TmpVal-trunc(TmpVal))*1000;
        TmpVal := TmpVal;
        if TmpVal<10 then
          TmpStr := TmpStr + ':00' + inttostr(trunc(TmpVal))
        else if TmpVal<100 then
          TmpStr := TmpStr + ':0' + inttostr(trunc(TmpVal))
        else
          TmpStr := TmpStr + ':' + inttostr(trunc(TmpVal));
    
      end;
    
      Result := TmpStr;
    end;
    
    procedure TForm4.SelectFile(Sender: TObject);
    begin
      if SaveDialog1.Execute then
         edFile.Text := SaveDialog1.FileName;
    end;
    
    procedure TForm4.Button4Click(Sender: TObject);
    begin
      MemoLogs.Lines.Clear;
    end;
    
    procedure TForm4.InitSaveAndReload(Sender: TObject);
    var
      _start   : TDatetime;
      ARate    : PRate;
      filename : string;
      Stream   : TFileStream;
      i,L      : integer;
      rates_M1 : array of PRate;
      //rates    : array of PRate;
    begin
      filename := edFile.Text;
    
      MemoLogs.Lines.Add('Initialization of 7 million array of records... Please wait.');
      Refresh;
    
      // init array
      _start := Now;
      SetLength(rates_M1, 7000000);
      for i:= 0 to 6999999 do
      begin
        New(ARate);
        ARate.time        := DateTimeToUnix(IncMinute(Now, i));
        ARate.open        := 1.25698;
        ARate.low         := 1.2574;
        ARate.high        := 1.2547;
        ARate.close       := 1.65874;
        ARate.tick_volume := 154;
        ARate.spread      := 5;
        ARate.real_volume := 15741;
        rates_M1[i]       := ARate;
      end;
      MemoLogs.Lines.Add(IntToStr(Length(rates_M1)) + ' array of records initialized ' + TimeElapsedToString(MilliSecondsBetween(Now, _start), true));
    
      // save array
      _start:= Now;
      Stream:= TFileStream.Create(filename , fmCreate);
      try
        L:= Length(rates_M1);
        Stream.WriteBuffer(L, SizeOf(L));
        Stream.WriteBuffer(Pointer(rates_M1)^, L * SizeOf(ARate));
      finally
        Stream.Free;
        MemoLogs.Lines.Add(IntToStr(Length(rates_M1)) + ' records saved to disk in ' + TimeElapsedToString(MilliSecondsBetween(Now, _start), true));
      end;
    
      LoadFromFile();
    
    end;
    
    procedure TForm4.LoadFromFile;
    var
      _start   : TDatetime;
      ARate    : PRate;
      filename : string;
      Stream   : TFileStream;
      i,L      : integer;
      rates    : array of PRate;
    begin
      // reload array
      _start := Now;
      filename := edFile.Text;
      Stream:= TFileStream.Create(filename , fmOpenRead);
      try
        Stream.Read(L, SizeOf(L));
        //SetLength(rates_M1, L);
        // even use another empty array of ARate to be sure I am not using the same filled array!
        SetLength(rates, L);
        // I don't want to parse all records...
    //    for i := 0 to L-1 do
    //      begin
    //        Stream.Read(rates_M1[i].AID, SizeOf(ARecord.AID));
    //        Stream.Read(rates_M1[i].time, SizeOf(ARecord.time));
    //      end;
        Stream.Read(Pointer(rates)^, L * SizeOf(ARate));
      finally
        Stream.Free;
        MemoLogs.Lines.Add(IntToStr(Length(rates)) + ' records loaded from disk in ' + TimeElapsedToString(MilliSecondsBetween(Now, _start), true));
      end;
    
      // Print 20 first records just reloaded!
      MemoLogs.Lines.Add('Print 20 first records just reloaded in another array of records!' + TimeElapsedToString(MilliSecondsBetween(Now, _start), true));
      for i := 0 to 20 do
         MemoLogs.Lines.Add('i=' + IntToStr(i) + #9
                          + IntToStr(rates[i].time) + #9
                          + FloatToStr(rates[i].open) + #9
                           );
    
    end;
    
    procedure TForm4.Reload(Sender: TObject);
    begin
      LoadFromFile();
    end;
    
    end.
    

    Result

    当我说“不再有效”时,我的意思是一旦你调用了InitSaveAndReload()程序,就可以根据需要多次调用LoadFromFile(),但是如果你在启动应用程序之后调用这个程序,那么试试使用由InitSaveAndReload过程创建的旧文件,然后它不起作用!

    单位提供尽可能简单。只需创建一个新的projet添加3个按钮,一个TMemo和一个TEdit。如果我可以加入.rar,我会附上项目...

1 个答案:

答案 0 :(得分:2)

您正在保存每条记录的地址,而不是保存记录的内容。你有一个指针数组,并将该数组保存到文件中。使用当前的数据结构,您需要单独保存每条记录,因为实际数据不会连续存储在内存中。