Link to home
Start Free TrialLog in
Avatar of Miguel Oz
Miguel OzFlag for Australia

asked on

Convert object properties to delimited string and save results to file

Suppose we have a Customer obj with the following properties:
- Id
- Name
- Address

I would like to Convert object properties to delimited string with a object method like:

function Customer.ToString(const aDelimiter: Char): string;
begin
  //SAmple code for csv, need change to use aDelimiter parameter
  Result := Format("%s,%s,%s",Id, Name, Description);
end;

where aDelimiter can be ",", ";", tab(\t), etc.

Notice that the result string will be stored in a stringlist later on to be output to a file. For example the Pseudo code:
csvList := TStringList.Create;
foreach customer in CustomerList
  csvList.Add(customer.ToString(',');
csvList.SaveToFile("CustomerExport.csv");

There are thousands of lines to store from CustomerList, any ideas on how to make it this export more efficient will be greatly appreciated.
Note: Compiler is still Delphi 7.
Avatar of Ephraim Wangoya
Ephraim Wangoya
Flag of United States of America image


I dont think you can get alot more efficiency out of a sequential list. You have to iterate all the objects in any case.
However you can eliminate the saving to stringlist, save it straight to a file, this will be much faster

You could make the object much better by adding the save method to the CustomerList object and let the methods of the List handle the iteration and also set the delimiter once in the CustomerList Object

private
   FDelimiter: Char;
   function GetText: string;
public
    procedure SaveToFile(const AFileName: string);
    .....
    property Delimiter: char read FDelimiter write FDelimiter;
end;





function TCustomerList.GetText;
var
  L, Size, Count: Integer;
  P: PChar;
  S, LB: string;
begin
  Count := GetCount;
  Size := 0;
  LB := #13#10;
  foreach customer in CustomerList
    Inc(Size, Length(Customer.ToString(FDelimiter) + Length(LB));

  SetString(Result, nil, Size);
  P := Pointer(Result);
  foreach customer in CustomerList
  begin
    S := Customer.ToString(FDelimiter;
    L := Length(S);
    if L <> 0 then
    begin
      System.Move(Pointer(S)^, P^, L);
      Inc(P, L);
    end;
    L := Length(LB);
    if L <> 0 then
    begin
      System.Move(Pointer(LB)^, P^, L);
      Inc(P, L);
    end;
  end;
end;


procedure TCustomerList.SaveToFile(const AFileName: string);
var
  Stream: TFileStream;
  S: string;
begin
  Stream := TFileStream.Create;
  try
    S := GetText;
    Stream.WriteBuffer(Pointer(S)^, Length(S));
  finally
    FreeAndNil(Stream);
  end; 
end;

Open in new window

Avatar of Miguel Oz

ASKER

Your code does not implement Customer.ToString method using the delimiter parameter.
If you can add thta to your answer will be great
Thanks.

Since Delimiter is already a property of the CustomerList and is accessed within the method GetText, you just set and call SaveToFile


  CustomerList.Delimiter := ',';
  CustomerList.SaveToFile('c:\CusomerExport.csv');
The delimiter is only for the customer properties.
Your posted code use this construct:
Customer.ToString(FDelimiter)
but the implementation (ToString method at Customer object) is not posted. The main objective of this question is how to convert the object to string taking in consideration that this string will be later used in a big list to save it to a file.
SOLUTION
Avatar of Ephraim Wangoya
Ephraim Wangoya
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
You can use a TStringList to build your delimited string. It requires a delimiter, and also a quote in case there can be occurences of the delimiter in the values (the address might contain coma, for example)
the resulting string could then be :

1;John Smith;"123, main street road"
function TCustomer.ToString(Delim:Char=',';Quote:Char='"'):String;
Var
 L:TStringList;
begin
 L:=TStringList.Create;
 L.Delimiter:=Delim;
 L.QuoteChar:=Quote;
 L.Add(IntToStr(ID));
 L.Add(Name);
 L.Add(Address);
 Result:=L.DelimitedText;
 L.Free;
end;

Open in new window

I use this method:
function Customer.ToString(const AFormat: string): string;
begin
  Result := Format(AFormat,  [Id, Name, Description]);
end;
where  AFormat = '%s,%s,%s'; or any other delimiter I need.Thus the formatiing string is build once and use multiple times

Thank you all for your comments. I will keep the question open a bit longer to see if there is any faster way to do this.
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Guideline without profile backing