Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi-拆分行(程序不响应),不拆分文件大小(TTHREAD)_Delphi - Fatal编程技术网

Delphi-拆分行(程序不响应),不拆分文件大小(TTHREAD)

Delphi-拆分行(程序不响应),不拆分文件大小(TTHREAD),delphi,Delphi,希望大家都做得很好。 我只有一个问题,在Delphi编程中。。。 我有一个备忘录,里面有一个文件.txt,里面有很多行,比如50000行 所以我想将这些行拆分为5000行,然后将它们加载到一个新的备忘录中。 例如,对于第一次拆分,它将在一个新的文件文本上拆分5000行,然后将其加载到一个新的备忘录上,加载后删除5000行的文件,当然,对于大的行,它将是45000行 第二次拆分它将从45000中拆分5000,在大行中为40000,在新行文件文本中为5000 我之所以要拆分文件文本上的行,然后再加载

希望大家都做得很好。 我只有一个问题,在Delphi编程中。。。 我有一个备忘录,里面有一个文件.txt,里面有很多行,比如50000行

所以我想将这些行拆分为5000行,然后将它们加载到一个新的备忘录中。 例如,对于第一次拆分,它将在一个新的文件文本上拆分5000行,然后将其加载到一个新的备忘录上,加载后删除5000行的文件,当然,对于大的行,它将是45000行

第二次拆分它将从45000中拆分5000,在大行中为40000,在新行文件文本中为5000

我之所以要拆分文件文本上的行,然后再加载它,是因为当我将文件拆分到备忘录中时,程序没有响应也没有响应

procedure TForm1.Button1Click(Sender: TObject);
var count,i ,X,m:integer;
begin
Memo2.Clear;
Label1.Caption:=IntToStr(Memo1.Lines.Count) ;
if Memo1.Lines.Count > 5000 then
X:=5000
else X:= Memo1.Lines.Count ;
for  count:=0 to x do
  begin

  Memo2.lines.add(Memo1.lines.Strings[0]);
  Memo1.Lines.Delete(0);

             Memo2.Text:=Trim(Memo2.text);

end;
end;
这是我用来将小行分割成其他小行的代码

在备忘录中,但当你有100万行时,程序将停止应答

我添加了trimmoom2.text;删除末尾的空行。

因此,我如何才能进行行的拆分,而不是文件大小的拆分,因为它会破坏行。。。我怎么能像我说的那样把大行分割成文件文本,然后加载并删除它,然后当我重新单击一个按钮时,它会对其他行执行相同的操作

我知道我们必须使用TThread类,但我不知道如何在我的代码中实现它。。。谢谢你


谢谢。

您可能达到了tmemo的极限,这取决于您使用的是哪个版本的Delphi。当然,从tmemo中删除第一行需要时间,尤其是5000次


对于前5000行和备忘录2,您是否考虑使用ReLLN和WrrEnn到备忘录2,如果存在的话?

< P>线程不是问题的答案。此任务不需要线程。问题在于:

Memo1.Lines.Delete(0);
在循环中执行此操作对于备忘来说非常昂贵。文本的第一部分被删除,其余部分向上移动

最好的办法是:

将整个源移动到TStringList。 将该字符串列表的前5000行处理为单个字符串。 使用SelText:=..一次性将整个字符串添加到备忘录中。。。。 完成后,只需一次通话即可清除原始备忘录

如前所述

使用TStringList加载和处理数据,使用TMemo显示数据

记住:如果你做不到,那就假装吧

而且你不能在合理的时间内将50000条线路加载到一个标准VCL控件中

因此,我为您制作了一个小样本应用程序,向您展示如何伪造它:

您需要在演示中添加错误处理,我只是选择了最短和最乐观的路径

首先,我需要一些数据,所以我生成了一个包含随机数据的文件:

procedure TForm25.GenereateTextFile(const aLines: Integer);
var
  Buffer: TStringlist;
  Line: string;
  i, j: Integer;
begin
  Buffer := TStringlist.Create;
  try
    for i := 1 to aLines do
    begin
      SetLength(Line, Random(200));
      for j := 1 to Length(Line) do
        Line[j] := Chr(ord('a') + Random(26));
      Buffer.Add(Line);
    end;

    Buffer.SaveToFile('dummy.txt');
  finally
    Buffer.Free;
  end;
end;
我称之为表单创建:

procedure TForm25.FormCreate(Sender: TObject);
begin
  GenereateTextFile(50000);
end;
然后我们需要生成一些GUI以显示文件:

在窗体上放置一个TTimer,并将其间隔设置为50,然后为其分配一个OnTimer事件

程序TForm25.Timer1TimerSender:ToObject; 开始 Timer1.Enabled:=False; GenerateGUISelf,'dummy.txt'; 结束

剩下的就是生成实际的GUI:

procedure TForm25.GenerateGUI(const aForm: TForm; const aFileName: TFilename; aLinesPerPage: Integer = 5000);
var
  Buffer: TStringlist;
  Tmp: TStringlist;
  i, j: Integer;
  PageControl: TPageControl;
  TabSheet: TTabSheet;
  Memo: TMemo;
begin
  Buffer := TStringlist.Create;
  Buffer.LoadFromFile(aFileName);
  Buffer.BeginUpdate;

  PageControl := TPageControl.Create(aForm);
  PageControl.Parent := aForm;
  PageControl.Align := alClient;
  i := 0;

  for i := 0 to (Buffer.Count div aLinesPerPage) - 1 do
  begin
    TabSheet := TTabSheet.Create(PageControl);
    TabSheet.PageControl := PageControl;
    TabSheet.Caption := Format('Lines %d to %d', [i * aLinesPerPage, (i + 1) * aLinesPerPage - 1]);

    Memo := TMemo.Create(TabSheet);
    Memo.Parent := TabSheet;
    Memo.Align := alClient;

    j := 0;

    Tmp := TStringlist.Create;
    Tmp.BeginUpdate;
    Application.ProcessMessages;

    while j < aLinesPerPage do
    begin
      Tmp.Add(Buffer[0]);
      Buffer.Delete(0);
      inc(j);
    end;

    Memo.Lines.Assign(Tmp);
    Tmp.Free;
    Application.ProcessMessages;
  end;
  FreeAndNil(Buffer);
end;
您将看到页面逐个显示并显示数据


它一个接一个出现的原因是我调用Application.ProcessMessages;它会让事情变慢一点,但不会太慢,你会告诉你的用户这个程序还活着

我不确定TMemo的使用对应用程序有多重要,但如果您只想将一个文本文件拆分成几个行数相同的文件,除了最后一个,当然,您根本不需要TMemo,也不需要任何像TStringList或TStream这样的Delphi容器类。关键是,您已经有了一个非常好的容器,即文件系统

下面是一个Delphi控制台应用程序,它使用Object Pascal中的文件访问方法,因为在Delphi之前,我可以听到一些Delphi粉丝啧啧地说我用这种方式向您演示,但我认为找到其他完全有效的方法是没有坏处的,特别是因为这避免了进入Delphi容器类的语义和用法

希望它的工作原理不言而喻。创建测试文件后,它逐行将其读回,并将其输出到一个按顺序编号的输出文件,直到该文件中的行数达到您想要的数量,或者没有更多的行可供读取。在我的便携式电脑上,从开始到结束需要0.078秒

代码:


线程不是解决方案,因为如果不与主线程同步,线程就无法与GUI控件交互,这违背了使用线程的目的。为什么需要使用备忘录分割内容?用户显然不能同时看到所有的备忘控件。您的代码的目的是什么?显示与拆分为文本文件无关。我将重试。还不清楚你是否需要记忆

o从您的帖子中获取一个可视控件。现在还不清楚你是在试图向用户显示内容,还是仅仅错误地试图使用备忘录来做错误的事情。所以我要再次问:你的实际目标是什么?是否要向用户显示备忘录中的内容?是否要播放互动程序的内容?你能读懂我一直问你的那些你似乎一直忽视的问题吗?你到底想干什么?如果你不愿意解释,你的问题就不属于这里。请澄清你的问题,说明你的目标是*向用户显示备忘录的内容并正确使用,还是错误地使用备忘录来执行其他任务。到目前为止,您的帖子和评论没有澄清您是否只是正确地使用了UI控件,或者您是否做了一些完全错误的事情,用户在过程中使用了UI控件,并且多次尝试要求您澄清似乎失败了*这些东西中哪一件是你的你想做什么?它们是独立的,不同的东西,所以只有一个选择。你选择哪一个?线程不是答案。备忘录不是答案。如果你停止玩游戏,明确你的要求,我们可能会提供帮助。例如,我经常处理大于1GB的文件,并允许用户浏览内容。。如果你能像我以前问过好几次的那样,简单地说清楚你在问什么,我相信这里会有人帮你。如果你继续固执,那么让我们结束这个问题,转向那些真正需要我们帮助的人——TMemo没有极限。自Windows 2000以来,没有限制。是的,删除第一行true需要时间,这就是为什么我们必须使用一些tthread类,这意味着拆分成文件文本,而不是备忘录,因为它使用内存。是的,对TMemo没有限制,只要你从Tstring中添加行,对于加载来说,我对代码做了什么没有限制,首先是在备忘录中加载文件文本。所以大约50000行…当加载大文件时,程序也开始阻塞,所以在一个备忘录中,我从备忘录中分割了5000行。现在备忘录上有5000行,备忘录上有45000行!!!!!。。。。但是从50000行到5000行需要很多时间…我只是想让它更快!我就是这么说的TThread@John在GUI控件中处理文本的速度非常慢。从备忘录顶部删除文本很慢。不要那样做。这不是这个网站真正的目的。对不起,那你该学了。本网站旨在供程序员使用。如果您不知道如何编写代码和学习,那么它就不适合您。在这种情况下,你需要雇佣一名程序员。@JohnGOLFOil-请不要再要求David提供代码来骚扰他了。他给了你一个答案,由你来实施。我们都是这里的志愿者。很高兴他花时间以任何方式回答你。这些评论现在应该停止了。他开始在Facebook上向我发送垃圾邮件。他至少十次叫我种族主义者,现在他不明白我不会是他的朋友。@Jens很难理解。可能需要治疗。很好的代码,只是需要一些小的更改…我想分割行,而不是文件大小,因为这是差异项,当你分割行时,你从源代码中获取行,当你分割文件大小时,文件和文件之间的差异会使行被破坏…所以我想从50000个源代码中剪切5000行。当我点击一个按钮。当我点击第三次时,我的代码将从45000中取出5000,当我点击第三次时,它将取出5000,剩下35000等等。我不确定你试图在线条和大小之间画出什么区别——我的代码将工作,而不考虑单个线条的长度。但是无论如何,当你把大文件分割成小文件时,在一个文件和另一个文件之间,最后一行就会被销毁。但是,当你每次点击一个按钮,从50000行中取出5000行时,它将非常好,没有被破坏的行。那么你的代码能完成这项工作吗?例如,从50000行削减5000行?事实上,我不确定你是否了解发生了什么。这段代码根本不会破坏任何东西,它只是将行从一个文件复制到另一个文件。顺便说一句,这让我想知道为什么?上周这里的一条线索是关于将备忘录结合在一起。在这种情况下使用备忘录也是完全没有必要的。不管怎样,我做完了。祝你好运我不明白?如何从按钮调用该过程,你的意思是当我点击一个按钮时,我启用了计时器?在表单上放置一个按钮,点击两次,然后编写以下代码:GenerateGUISelf,'dummy.txt';什么是dummy.txt,我可以带我的50000行?或者我必须做第一个代码来生成这些随机行?因为我不需要随机行…用文件的真实名称替换dummy.txt。@Jens请重新考虑。请不要喂吸血鬼。
program FileSplit;

{$APPTYPE CONSOLE}

uses
  SysUtils;

const
  MaxLines = 100000;
  LinesPerFile = 5000;
  BufferSize = 32768;

var
  MainFileName : String;

procedure CreateFile(AFileName : String);
var
  AFile : Text;
  Line : Integer;
  Buffer : Array[1..BufferSize] of Char;
  S : String;
begin
  AssignFile(AFile, AFileName);
  SetTextBuf(AFile, Buffer, SizeOf(Buffer));
  Rewrite(AFile);

  Line := 1;
  while Line <= MaxLines do begin
    S := Format('This is line: %d', [Line]);
    writeln(AFile, S);
    Inc(Line);
  end;
  Close(AFile);
end;

procedure SplitFile(AFileName : String);
var
  AFile : Text;
  SubFileNumber : Integer;
  Buffer : Array[1..BufferSize] of Char;

  procedure CreateSubFile(SubFileNumber : Integer);
  var
    OutFile : Text;
    OutBuffer : Array[1..BufferSize] of Char;
    SubFileName : String;
    S : String;
    Line : Integer;
  begin
    SubFileName := ExtractFilePath(AFileName) + IntToStr(SubFileNumber) + '.Txt';
    writeln(SubFileName);

    Assign(OutFile, SubFileName);
    SetTextBuf(OutFile, OutBuffer, SizeOf(OutBuffer));
    Rewrite(OutFile);

    Line := 1;

    // the following reads the input file a line at a time
    // and outputs it to the current output file
    // until there's nothing left to read or the lines
    // per output file is reached

    while (Line <= LinesPerFile) and not Eof(AFile) do begin
      readln(AFile, S);
      writeln(OutFile, S);
      Inc(Line);
    end;

    Close(OutFile);
  end;

begin
  Assign(AFile, AFileName);
  SetTextBuf(AFile, Buffer, SizeOf(Buffer));
  Reset(AFile);

  SubFileNumber := 1;
  while not Eof(AFile) do begin
    CreateSubFile(SubFileNumber);
    Inc(SubFileNumber);
  end;
  Close(AFile);
end;

begin
  MainFileName:= GetEnvironmentVariable('Temp');
  MainFileName := IncludeTrailingPathDelimiter(MainFileName);
  MainFileName := MainFileName + 'Main.Txt';

  CreateFile(MainFileName);
  writeln(Format('File %s created', [MainFileName]));

  SplitFile(MainFileName);
  readln;

end.