本帖最后由 miaotouyang 于 2014-01-13 07:53:52 编辑

解决方案 »

  1.   

    StringBulder: TStringBuilder;比如
    for i:=1 to j do
      StringBuilder.Append('abcdefg'+'0x'+IntToHex(i,2));result:=StringBuilder.ToString;它的概念很简单,就是连续内存把所有字符串都存好,
    暂时不取用,直到取用时一次性赋值给String.
    我没测过,但从理论上来说应该是能解决你的问题。至于Delphi从哪一个版本开始提供StringBuilder,
    那我就不知道了,
    你自己看看你用的版本有没有啰。依我的想法,
    就算你用的版本没有支持,
    去有支持的版本copy source过来,
    估计也可以。
      

  2.   

    procedure TForm1.Button4Click(Sender: TObject);
    var
      s: string;
      i: integer;
    const
      j = 10000;
    begin
      Button4.Enabled := False;
      ProgressBar1.Max := j;
      for i := 0 to j do
      begin
        s := s + 'abcdefg' + '0x' + IntToHex(i, 2);
        ProgressBar1.Position := i;
        Application.ProcessMessages;
      end;
      Button4.Enabled := True;
    end;
      

  3.   

    frank_lee_cn胸
    版本是delphi7,没有StringBuilder 类,我按“F1”没有帮助提示。
    你的思路是对的,
    我想过用字符数组来,每个字符长度是一定的就是0x00,不知道该怎么写数组,请教了。
      

  4.   

    回sz_haitao,效果没有改善,我代码对吧?
    procedure TForm1.Button4Click(Sender: TObject);
    var
       s ,str:string;
       i :integer;
    const
       j = 10000;
    begin
        ProgressBar1.Max:=j;
        s := '';
        str := '';
        for i:=0 to j do
        begin
            if (i mod 1000) = 0 then
             begin
             str := str + s;
             s  :='';
             end
            else
             begin
              s := s + 'abcdefg'+'0x'+IntToHex(i,2);
             end;     progressbar1.Position:= i;
        end;end;
      

  5.   

    我的程序是从bmp读数据转成c数组做的小工具,
    读到bmp后就知道整个字符串长度了,
    如果是
    bgr :array of byte; 
    setLength(bgr, size);
    我知道怎么用,但字符串不知道了
      

  6.   


    procedure TForm1.Button4Click(Sender: TObject);
    var
       s ,str:string;
       i :integer;
    const
       j = 10000;
    begin
        ProgressBar1.Max:=j;
        s := '';
        str := '';
        for i:=0 to j do
        begin
              s := s + 'abcdefg'+'0x'+IntToHex(i,2);
            if (i mod 1000) = 0 then
             begin
    progressbar1.Position:= i; //移到这里!
             str := str + s;
             s  :='';
             end;
        end;
    if s<>'' then
      str:=str+s;
    end;
      

  7.   


    一样
    setlength(str,n*(7+2+2)); //7:'abcdefg'+2:'0x'+2:IntToHex(i,2)
    for i:=...
    begin
    p:=(i-1)*11;
    str[p+1]:='a';
    str[p+2]:='b';
    ...
    end;
      

  8.   


    procedure TForm1.Button4Click(Sender: TObject);
    var
      a: array of char;
      L: integer;
      S: String;
      i: integer;
    const
      j = 10000;
    begin
      L:=0;
      Button4.Enabled := False;
      ProgressBar1.Max := j;
      for i := 0 to j do
      begin
        S:='abcdefg' + '0x' + IntToHex(i, 2);
        SetLength(a, L+Length(S));
        for x:=1 to Length(S) do
          a[L+x-1]:=S[x];
        L:=L+Length(S);
        ProgressBar1.Position := i;
        Application.ProcessMessages;
      end;
      SetLength(a, L+1);
      a[L]:=#0;
      S:=String(A);
      Button4.Enabled := True;
    end;
    上面是我参考StringBuilder的概念随手写的代码,
    没有Debug,肯定有很多错,只是用以表达我的想法,
    说明“连续内存把所有字符串都存好最后一次取用”的概念。觉得你还是直接把TStringBuilder代码取来用比较简单。
      

  9.   

    反复setlength(char数组)也会导致内存分配释放吧?
      

  10.   

    > 反复setlength(char数组)也会导致内存分配释放吧?是。
    所以Delphi的代码通常不会一次只增加所需内存,
    而是需要时增加一块大一点的内存供使用,
    以此来减少SetLength执行次数。我上面随手写的代码不包含这个机制,
    但Delphi的代码里是有的,
    因此我一直强调直接用TStringBuilder更好。
      

  11.   


    progressbar1.Position:= i; //移到这里!
    不能移到mod里面,本来就是为了测试速度的。
      

  12.   


    能否帮我提取下TStringBuilder
      

  13.   

    frank_lee
    11楼你写的代码,没改善。也是一开始快,到后面慢。
      

  14.   


    我的测试方法有问题,刚才仔细看了你的代码,你是用数组方式来实现的,每次放进去的只是当前的字符,
    需要累加。我实际情况是每次字符串长度是固定的如:‘0x00,’共5个长度。不需要每次都setlength.
    接下来我按你的方法放到实际程序中,让它处理大bmp图片试试。
    稍后汇报。
      

  15.   

    frank_lee_cn 
    按你方法测试
    处理一个234*198的bmp图片,生成约680 000个数据需要30秒。按我自己原先方法是需要71秒;速度有提高,但还不够快,等半分钟是难易忍受的。有没有更好的办法?
      

  16.   

    procedure TForm1.Button4Click(Sender: TObject);
    var
      i: Integer;
      ss: TStringStream;
      s: string;
    const
      j = 10000;begin
      ss := TStringStream.Create('');
      try
         ProgressBar1.Max:=j;
        for i := 0 to j do
        begin
          ss.WriteString('abcdefg0x' + IntToHex(i,2));
          progressbar1.Position:= i;
        end;
        s := ss.DataString;
      finally
        ss.Free;
      end;
    end;使用TStringStream试试。
      

  17.   

    > 处理一个234*198的bmp图片,生成约680 000个数据需要30秒。先用图片的长宽,计算最大需要内存空间,
    只用一次SetLength
    其后都是填数据的过程。
      

  18.   

    > 处理一个234*198的bmp图片,生成约680 000个数据需要30秒。为什么要把bmp转成strings?
    想想有没有更好的方式。
      

  19.   

    procedure TForm1.Button2Click(Sender: TObject);
    var
      S , sBuf : String;
      i , iUsed , iLen , iMax : integer;
    const
      j = 1000000; //扩大了100倍
    begin
      ProgressBar1.Max := j;
      iUsed := 0;
      iMax := 0;
      for i:=0 to j do begin
        S := 'abcdefg'+'0x'+IntToHex(i,2);
        iLen := Length(S);
        if iLen+iUsed>iMax then begin
          inc(iMax , 1024*1024);
          SetLength(sBuf , iMax);
        end;
        {$IFDEF CPUX64}
        Move(Pointer(S)^ , Pointer(Int64(sBuf)+iUsed)^ , iLen * SizeOf(Char));
        {$ELSE}
        Move(Pointer(S)^ , Pointer(Integer(sBuf)+iUsed)^ , iLen * SizeOf(Char));
        {$ENDIF}
        inc(iUsed , iLen);
      end;
      Delete(sBuf , iUsed+1 , iMax);
      //到此,sBuf就是累加的结果了
    //这句移动到最后了,因为整个过程不到1秒,放到中间反而慢得很
      progressbar1.Position := progressbar1.Max;  
    end;
      

  20.   

    回22楼pathletboy ,用你的TStringStream试试。 贴上我处理图片代码
    ms:=TMemoryStream.Create; 
         bmp :=TBitMap.Create;   
         ms.Clear;
         s := OpenDialog2.FileName;
         ms.LoadFromFile(s); //装载对应路径下的图片
         ms.Position:=0;    
         bmp.LoadFromFile(s);//装载对应路径下的图片
         
               //处理bmp数据到bgr数组
               bmp_height := bmp.Height;
               bmp_width  := bmp.Width;
               sum  :=0;//总像素点数
               j:=1;           
               ProgressBar1.Max:=ms.Size;
               for i:=0 to bmp_height -1 do  //多少行
               begin
                     P := bmp.scanline[i];  //取行首地址指针
                     for  m:=0 to (bmp_width * 3)-1  do  //每行有多少点 ,24位色是3个字节一个像素。
                     begin     //用每行的点*3正好解决bmp数据存储4字节对齐问题
                     if ((j mod 16) = 0)  then   //每行16字节
                       begin
                         s := '0x'+ IntToHex(P[m],2)+','+#13#10;  //添加回车换行
                       end
                     else
                       begin
                          s := '0x'+ IntToHex(P[m],2)+',';                    end;
                   // ss.WriteString(s); //注释掉需要24秒,不注释61秒,
                                     //这个方法不如frank_lee_cn 的用a: array of char;方法
    //但我的程序IntToHex(P[m],2)估计废了不少时间,如果不用到这个转换函数,有什么方法把bmp的
    //数据转成C数组0x00这个样子?                progressbar1.Position:= j;
                    j :=j+1;
                    end;// for m:=0
               end; //for i:=0
      

  21.   

    受26楼start8588 启发,“排除UI影响”
    我前面的测试都是错误了,
    发现progressbar1.Position:= j; 这个才是耗时的罪魁祸首。
    我接下来去掉进度条重新测试一遍各位提供的方法。
      

  22.   

    frank_lee_cn 你的方法现在转换很快,不需要1秒,只是转换出来的数据和我原先不一样了。
    被你这一步弄坏了S:=String(A);,还有方法么?
    看:
    s := '0x'+ IntToHex(P[m],2)+','+#13#10;  //添加回车换行 
    SetLength(a, L+1);
    a[L]:=#0;
    S:=String(A);
      

  23.   


    所以要
    if j mod 1000=0 then
      progressbar1.Position:= j;
      

  24.   

    pathletboy 
    的ss := TStringStream.Create('');方法去掉后
    进度条测试转换图片数据需要46秒,但转换出来的数据是符合我要求的。
      

  25.   


    所以要
    if j mod 1000=0 then
      progressbar1.Position:= j;

    你说的有道理,昨天没有理解你的意思,现在想想你说的对。
      

  26.   

    > 被你这一步弄坏了S:=String(A);,还有方法么?应该不是S:=String(A)那行错误。
    因为出现了好几个0,
    感觉比较可能是下面这二行的错。
    for x:=1 to Length(S) do
      a[L+x-1]:=S[x];
    昨天写的时候告诉你我没Debug了,(只是随手在网上写的,没有运行IDE)
    你应该自己设法debug才是。我通常在论坛回复,
    不会给那么精准的答案,
    只是表达意思而已,
    Debug得你自己多伤脑筋才是。另,27楼好像给了你很棒的答案,
    何不参考?
      

  27.   

    看懂27楼kiboisme 代码了,用指针传的方式,用他方法,确实很快,不用一秒,数据转出来也对的。
    与frank_lee_cn 代码对比的话,两种思路是一个是指针,一个是数组,字符需要不停累加,只追加在字符串尾。在C语言里从根本上来讲数组和指针是差不多的,不敢说一样,记得网上有大神专门反驳过。
    本例程序还是指针方式好,对原数据没有进行转变,只是搬运。
    结贴,谢谢各位热心帮忙,只有20分平分给大家了,分数只是小事,让大家看到你们的热情才是值得发扬的。
      

  28.   

    因为CSDN的问题,27楼kiboisme 给分的框被挡住了,给不了你。见谅。