我在使用一个字符串之前用SetLength(TmpRow,80);分配了长度;对于最后结果我想要的是诸如:“99999999|NULL|800004061611|xxx建筑劳务有限公司|1  |NULL|2009-2-13|1”这个样子,但在最后出来的结果中却变成了:“99999999|NULL|800004061611|xxx建筑劳务有限公司|1  |NULL|2009-2-13|1MemoMemo2LeftTopWidth?Height?Lines.StringsMemo2”,也就是在我想要的结果后面多了一串东西。我用Trim(TmpRow)也没有用,请问该怎么处理。不要说先用一个变量来记录真实的长度,最后再用copy函数来截取。我的字符串很长,且记录条数很多,我还要往文件里面写,要考虑效率的问题,谢谢!

解决方案 »

  1.   

    即然字符串很長,為什麼不直接用STRING類型的變量。 
      

  2.   

    长度不是不够,而是太长了,我帖子里面写的80,实际上我程序里面长度定的是1000。我不是直接使用的string,因为我要拼凑字符串,如果使用:string1 + string2这种方式的话会比较慢,我是这样用的://拼凑字符串,FieldsValue是读取的表中的一个字段
    for m := 1 to FieldsValueLen do
    begin
       TmpRowLen := TmpRowLen + 1;
       TmpRow[TmpRowLen] := FieldsValue[m];
    end;
    所以,如果不在之前用SetLength分配长度的话会报错的。
      

  3.   

    4楼的兄弟,如果用fillchar来填充,那和用一个变量来记录真实的长度,最后再用copy函数来截取那不是差不多?我每一条字符串最后都要写个循环来填充,几十万行记录那不是比较慢?
      

  4.   

    setlength并没有对数组初始化,你需要现对数组初始化,你可以使用AllocMem
      

  5.   

    你能不能把代碼再貼清楚,類型也帶上來SETLENGTH就是最終也是分配內存,這是肯定的。
      

  6.   


    這裏的FieldsValueLen 是不是最大值呢?是的話為什麼不 SetLength(tmpRow,fieldsValuelen); 本身 setLength  是可以增加一個分配一個的。 當然你為了效率這可以不考慮了。我實再是想不通你上面的代碼能達到什麼效率。要麼你用 TStringList  來管理也許也行。 定義記錄定弄再做數組也可以。
      

  7.   


    FieldsValue[m]是什么类型的值? 如果是String类型的话, 你的代码得修改一下:SetLength(TmpRow, 10000);
    ......
    TmpRowLen := 0;
    for m := 1 to FieldsValueLen do 
    begin 
      Move(FieldsValue[m][1], TmpRow[TmpRowLen + 1], Length(FieldsValue[m]);
      TmpRowLen := TmpRowLen + Length(FieldsValue[m]); 
    end; 
      

  8.   


    for m := 1 to FieldsValueLen do
    begin  
     SetLength(TmpRow,Length(TmpRow)+1); 
      TmpRow[High(TmpRow)] := FieldsValue[m];
    end; 
      

  9.   

    非常感谢各位朋友的帮助,我把我要达到的目的说一下:一个表有30多个字段,接近50万条记录,由于要做一些特殊的处理,直接用DB2的export把数据导出来虽然很快,但满足不了要求,我只有自己来处理,所以我非常关心效率的问题。应starluck的要求,我把程序中最主要的两个函数贴出来,一个是从表中读取数据拼凑字符串,另一个是写文件的函数,大家顺便帮我看看哪些地方效率会比较底,再次感谢:
    procedure TableToFile(var OpenQuery : TADOQuery; SqlStr : string; TimeSeqNum : TimeCols; ff : integer);
    var
       FieldsCnts: integer;             //字段总数
       m, i : integer;                  //控制循环
       DotLocation : integer;           //需要修正的时间字段中'.'的位置
       ErrorMsg, FieldsValue : string;  //FieldsValue:从表中读取的一个字段
       FieldsValueLen : integer;        //FieldsValue的长度
       TmpRow : string;                 //准备写入文件的一行
       TmpRowLen : integer;             //TmpRow的长度
       e : integer;
    begin
       //创建文件并写标题行
       WriteToFile(FirstRowGather(ff), True, TouchFileName(ff));
       WriteToFile(ReturnNewLine, False, '');     ////写入一个回车换行符   with OpenQuery do
       begin
          Close;
          Sql.Clear;
          Sql.Add(SqlStr);
          Prepared := True;      try
             open;
          except
             on E: Exception do
             begin
                ErrorMsg := '查询数据失败,程序即将退出!' + #13 + E.Message;
                Application.MessageBox(PChar(ErrorMsg),PChar(Application.Title),MB_ICONERROR);
                Form1.Button1.Enabled := True;
                Application.Terminate;
             end;
          end;      FieldsCnts := Fields.Count;      //字段总数
          First;
          FieldsDel := '|';      while not EOF do
          begin
             TmpRow := '';                 //初始化写入文件中的一行为空
             SetLength(TmpRow,1000);
             TmpRowLen := 0;         for i := 0 to FieldsCnts - 1 do
             begin
                FieldsValue := OpenQuery.Fields[i].AsString;   //读取一个字段            //判断字段是否为空,为空则用NULL替换
                if FieldsValue = '' then FieldsValue := 'NULL';            //判断当前读取字段是否是需要修正的时间字段
                if i in TimeSeqNum then
                begin
                   DotLocation := pos('.', FieldsValue);       //获取时间字段中'.'所在的位置
                   if DotLocation > 0 then
                      FieldsValue := copy(FieldsValue, 1, DotLocation - 1);   //截取在'.'之前的字符串
                end;            FieldsValueLen := length(FieldsValue);         //获取字段长度            //这一段就是我帖子里面问的问题
                for m := 1 to FieldsValueLen do
                begin
                   TmpRowLen := TmpRowLen + 1;
                   TmpRow[TmpRowLen] := FieldsValue[m];
                end;            e := i;            //添加分割符号,最后一个字段后面不用添加
                if i < FieldsCnts - 1 then
                begin
                   TmpRowLen := TmpRowLen + 1;
                   TmpRow[TmpRowLen] := FieldsDel[1];
                end;
             end;
             form1.Memo2.Lines.Add(Trim(TmpRow));
             showmessage(inttostr(length(TmpRow))) ;         //********************************************
             //往文件中写入字符串,不写标题行也不需带文件名
             WriteToFile(TmpRow, False, '');         //写入一个回车换行符
             WriteToFile(ReturnNewLine, False, '');
             //**********************************************}         Next;   //取下一条记录
          end;      Close;
       end;   FS.Free;
    end;///////写文件的函数
    procedure WriteToFile(FileRows : string; NeedCreate : boolean; FileName : string);
    var
       Pstr : Pchar;
    begin
       if NeedCreate then          //判断是否需要创建文件流
       begin
          if FileExists(FileName) then DeleteFile(FileName);     //有文件则删除
          FS := TFileStream.Create(FileName, fmCreate);
       end;
       FileRows := FileRows;
       Pstr := Pchar(FileRows);
       FS.Writebuffer(Pstr^,Length(Pstr));
    end;
      

  10.   

    下面这段效率很低:            FieldsValueLen := length(FieldsValue);        //获取字段长度             //这一段就是我帖子里面问的问题 
                for m := 1 to FieldsValueLen do 
                begin 
                  TmpRowLen := TmpRowLen + 1; 
                  TmpRow[TmpRowLen] := FieldsValue[m]; 
                end; 
    修改成:          FieldsValueLen := length(FieldsValue);        //获取字段长度 
               Move (FieldsValue[1], TmpRow[TmpRowLen + 1], FieldsValueLen);
               TmpRowLen := TmpRowLen + FieldsValueLen; 
      

  11.   

    导致问题的也不是你最早帖出的那段, 而是这句:        //往文件中写入字符串,不写标题行也不需带文件名 
            WriteToFile(TmpRow, False, ''); 
    这里的TmpRow是长为1000的字符串, 而这1000个字符并未都被赋过值
    修改为:        //往文件中写入字符串,不写标题行也不需带文件名 
            WriteToFile(Copy(TmpRow, 1, TmpRowLen), False, ''); 
      

  12.   

    WriteToFile里再加个长度参数:procedure WriteToFile(const FileName: string; NeedCreate: Boolean; const FileRows: string; StrLen: Integer = 0); 
    begin 
      if NeedCreate then
         FS := TFileStream.Create(FileName, fmCreate); { 用不着先delete,fmCreate就够了 }
      if (StrLen<=0) then
        StrLen := Length(FileRows);
      FS.Write(FileRows[1], StrLen);
    end;写入的时候不要用Length,直接用你的TmpRowLen就可以了
      

  13.   

    15楼对的。
    或者最后再按实际大小调用一次SetLength
      

  14.   

    已向jadeluo和Seamour加分,谢谢各位无私帮助