RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1602605
Accepted
Viktor Tomilov
Viktor Tomilov
Asked:2024-12-16 23:40:24 +0000 UTC2024-12-16 23:40:24 +0000 UTC 2024-12-16 23:40:24 +0000 UTC

再次在 Delphi 中使用整数和内存进行耙子。 TStringList.LoadFromFile

  • 772

似乎这里的一切都已经被考虑和尝试过了。但我又遇到了一把旧耙子。 Delphi 11/12,处理大型文本文件。

简单代码:

var slist:TStringList;
       slist:=TStringList.Create;
       slist.LoadFromFile(ParamStr(1));

导致错误 Exception EIntOverflow in module PrimitiveMotif.exe at 0000000000010DEA,版本 11 中的整数溢出,以及错误 Exception EAbstractError in module PrimitiveMotif.exe at 0000000000044191,抽象错误在版本 12 中。

该文件是文本。是的,巨大(就像我们所有人一样)。但“仅”1.5 GB,FAR 仅显示 1800 万行,这非常符合 TStringList 的限制。计算机上的内存 - 已满 (192 GB)。去哪里挖?

PS 字符串 - ANSI

windows
  • 1 1 个回答
  • 53 Views

1 个回答

  • Voted
  1. Best Answer
    MBo
    2024-12-17T01:30:06Z2024-12-17T01:30:06Z

    如果你看看它是如何工作的TStrings.LoadFromFile,它会将LoadFromStream文件的内容加载 () 到一个字节数组中,然后将该数组转换为一个字符串GetString,然后解析 Unicode 字符串(我可能还没有考虑到所有步骤)。因此,内存中同时存在文件大小的三到四倍,分配了三到四个连续的千兆字节内存块 - 这不是很聪明或聪明,而且内存管理器似乎无法应对。

    但是,如果您需要在内存中保留这样的 TStringList,您可以从文件中逐行读取到列表中:

    • 像 Readln 这样的旧方法 - 现在不推荐这样做

    • 逐行独立地解析文件(我曾经从内存映射的巨型日志文件中读取,它比 ANSI 行时代的 Readln 快三倍,即使在 32 位时代也根本不可能完全读取这些文件)

    • 使用TStreamReader.ReadLine- 这可能是就劳动力成本而言最优化的方法,我还没有在速度方面对其进行测试。

    • 再次,使用David Heffernan精心开发的 BufferedFileStream 逐行独立解析文件

    PS 但同时需要所有线路?数据库在这里不起作用?

    一个小测试。创建一个 4 GB 大小的文件,包含 1600 万行长度为 256 的 Ansi 行(包括 CRLF)。

    //создаём файл
    procedure TForm2.Button1Click(Sender: TObject);
    var
      s: AnsiString;
      i: Integer;
      f: TextFile;
    begin
       AssignFile(F,'d:\testlong.txt');
       ReWrite(F);
       for i := 1 to 16*1048576 do begin
         s := StringOfChar(AnsiChar(48 + i mod 10), 254);
         Writeln(f, s);
       end;
       CloseFile(F);
    end;
    
    procedure TForm2.Button2Click(Sender: TObject);
    var
      s: AnsiString;
      i: Integer;
      f: TextFile;
      sl: TStringList;
      t: DWord;
      Buff: array[0..4095] of Char;
    begin
      t := GetTickCount;
      sl := TStringList.Create;
      AssignFile(f, 'd:\testlong.txt');
      Reset(f);
    
      /////
      TTextRec(f).BufSize := SizeOf(Buff);
      TTextRec(f).BufPtr := @Buff;
      /////
    
      i := 0;
      while not Eof(f) do
      begin
        Readln(f, s);
        if i mod 4 = 0 then
          sl.Add(s);
        Inc(i);
      end;
      CloseFile(f);
      Memo1.Lines.Add((GetTickCount - t).ToString);
      Memo1.Lines.Add(sl.Count.ToString);
      for i := 0 to 7 do // control
        Memo1.Lines.Add(sl[i]);
      sl.Free;
    end;
    
    
    procedure TForm2.Button3Click(Sender: TObject);
    const
      BufSize = 1048576;
    var
      st: TReadOnlyCachedFileStream;
      Buf: TBytes;
      Readed, i, start, cnt: Integer;
      sl: TStringList;
      astr, aleft: AnsiString;
      t: DWord;
    begin
      t:= GetTickCount;
      sl := TStringList.Create;
      cnt := 0;
      astr := '';
      aleft := '';
      SetLength(Buf, BufSize);
      st := TReadOnlyCachedFileStream.Create('d:\testlong.txt');
      Readed := st.Read(Buf[0], BufSize);
      while Readed > 0 do begin
        start := IfThen(Buf[0] = 10, 1, 0);
        for i := 0 to readed - 1 do begin
          if Buf[i] = 13 then begin
            if cnt mod 4 = 0 then begin
              SetString(astr, PAnsiChar(@Buf[start]), i - start);
              sl.Add(aleft + astr);
              end;
            start := i + 2;
            aleft := '';
            inc(cnt);
          end;
        end;
        if start < readed then
          SetString(aleft, PAnsiChar(@Buf[start]), readed - start)
        else
          aleft := '';
        Readed := st.Read(Buf[0], BufSize);
      end;
      Memo1.Lines.Add((GetTickCount - t).ToString);
      Memo1.Lines.Add(sl.Count.ToString);
      for i := 0 to 7 do   //control
        Memo1.Lines.Add(sl[i]);
      for i := 0 to 7 do // control
        Memo1.Lines.Add(sl[sl.Count - i - 1]);
      st.Free;
      sl.Free;
    end;
    
    procedure TForm2.Button4Click(Sender: TObject);
    var
      Reader: TStreamReader;
      s: AnsiString;
      i: integer;
      sl: TStringList;
      t: DWord;
     begin
      t := GetTickCount;
      sl := TStringList.Create;
      i := 0;
      Reader := TStreamReader.Create('d:\testlong.txt', TEncoding.ANSI);
      while not Reader.EndOfStream do begin
        s := Reader.ReadLine;
        if i mod 4 = 0 then
          sl.Add(s);
        inc(i);
      end;
      Memo1.Lines.Add((GetTickCount - t).ToString);
      Memo1.Lines.Add(sl.Count.ToString);
      for i := 0 to 7 do   //control
        Memo1.Lines.Add(sl[i]);
      for i := 0 to 7 do // control
        Memo1.Lines.Add(sl[sl.Count - i - 1]);
      Reader.Free();
      sl.Free;
    
    end;
    

    使用具有 SATA 的 SSD 驱动器(其速度约为 600 MB/s)。

    Readln 在没有改进缓冲的情况下运行一分钟,在增加缓冲的情况下仅运行 8 秒。每第四行被检索一次。此时程序占用了2G内存,并没有崩溃。

    使用缓冲读取模块和使用 CRLF 的独立解析(更正的 LF 到达缓冲区的开头),它也可以在 6-8 秒内完成。

    使用 TStreamReader(尚未在 SSD 上测试)

    在 HDD 和较旧的计算机上,时间约为 28、21 和 24 秒。这接近磁盘带宽限制,因此 StreamReader 的行为相当正常。

    PS NewfangledTFile.ReadAllLines也无法完整读取该文件(读取方式与列表大致相同)。

    PPS 您还可以使用OmniThreads 作者的GPTextFile,但我认为您不会获得太多好处。原来的问题确实存在(EnSO 上的示例通常与我写的内容一致),但就您而言,目前您可以接受这样的事实:无需下载整个列表。

    • 7

相关问题

  • bat文件中的简单循环,键盘输入,比较。程序无法正常工作

  • 如何在没有 fn 的情况下删除按钮的工作?

  • OpenVPN 路由

  • CMD 换行符输入到控制台

  • 帮助编写声卡驱动程序

  • Windows 10 返回对注册表分支的访问权限

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5