CSV即Comma Separate Values,这种文件格式经常用来作为不同程序之间的数据交互的格式。
具体文件格式
每条记录占一行
以逗号为分隔符
逗号前后的空格会被忽略
字段中包含有逗号,该字段必须用双引号括起来
字段中包含有换行符,该字段必须用双引号括起来
字段前后包含有空格,该字段必须用双引号括起来
字段中的双引号用两个双引号表示
字段中如果有双引号,该字段必须用双引号括起来
第一条记录,可以是字段名
晚上临睡之前,写了两个方法,用来把EjunGrid的内容保存到CSV格式, 算法还优待优化,我在群里搞了一个擂台赛,比试一下大家的算法功底, 看谁写的算法最精妙,代码最简洁, 优胜者将获得EjunGrid个人版一套。
procedure SaveGridToCSV(Grid: TZjGrid; Stream: TStream;
const
ABounds: TRect); overload;
function EncodeStr( const s: string ): string ;
var
I, k: Integer;
begin
I : = Pos( ' " ' , s);
if I <> 0 then
begin
Result : = Copy(s, 1 , I) + ' " ' ;
Inc(I);
while I < Length(S) do
begin
k : = I;
I : = PosEx( ' " ' , s, I);
if I = 0 then
begin
Result : = Result + Copy(s, k, Length(s) - k + 1 );
Break;
end
else
begin
Result : = Result + Copy(s, k, I - k + 1 ) + ' " ' ;
Inc(I);
end;
end;
Result : = ' " ' + Result + ' " ' ;
end
else if Pos( ' , ' , s) <> 0 then
Result : = ' " ' + s + ' " '
else
Result : = s;
end;
var
iRow, iCol: Integer;
Text: string ;
begin
for iRow : = ABounds.Top to ABounds.Bottom do
begin
for iCol : = ABounds.Left to ABounds.Right do
begin
Text : = EncodeStr(Grid.Cells[iCol, iRow].Text);
if iCol <> ABounds.Right then
Text : = Text + ' , ' ;
Stream.Write(Text[ 1 ], Length(Text));
end;
Text : = # 13 # 10 ;
Stream.Write(Text[ 1 ], Length(Text));
end;
end;
procedure SaveGridToCSV(Grid: TZjGrid; const FileName: string ); overload;
var
Stream: TStream;
begin
Stream : = TFileStream.Create(FileName, fmCreate);
try
SaveGridToCSV(Grid, Stream, Rect(Grid.FixedColCount, Grid.FixedRowCount,
Grid.ColCount - 1 , Grid.RowCount - 1 ));
finally
Stream.Free;
end;
end;
// 从流中加载
procedure LoadGridFromCSV(Grid: TZJGrid; Stream: TStream; DestCoord: TPoint); overload;
var
s: string ;
sLen: Integer;
newLine: Boolean;
function FetchText(var I: Integer): string ;
var
k: Integer;
bQuote: Boolean;
begin
bQuote : = False;
newLine : = False;
k : = I;
while k <= Length(s) do
begin
if (s[k] = ' , ' ) and not bQuote then
begin
Result : = Copy(s, I, k - I);
I : = k + 1 ;
Exit;
end
else if (s[k] = ' " ' ) then
begin
if (k < Length(s)) and (s[k + 1 ] = ' " ' ) then
Inc(k, 2 )
else
begin
bQuote : = not bQuote;
Inc(k);
end;
end
else if (s[k] = # 13 ) and (k < Length(s)) and (s[k + 1 ] = # 10 ) then
begin
Result : = Copy(s, I, k - I);
newLine : = True;
I : = k + 2 ;
Exit;
end
else
Inc(k);
end;
Result : = Copy(s, I, k - I);
end;
var
I: Integer;
Text: string ;
iRow, iCol: Integer;
begin
sLen : = Stream.Size - Stream.Position;
Grid.Clear;
if sLen = 0 then Exit;
SetLength(s, sLen);
Stream.Read(s[ 1 ], sLen);
I : = 1 ;
iRow : = DestCoord.Y;
iCol : = DestCoord.X;
Grid.BeginUpdate;
try
while I <= Length(s) do
begin
Text : = FetchText(I);
if Text <> '' then
Grid.Cells[iCol, iRow].Text : = Text;
if newLine then
begin
Inc(iRow);
iCol : = DestCoord.X;
end
else
Inc(iCol);
end;
finally
Grid.EndUpdate;
end;
end;
// 从文件中加载
procedure LoadGridFromCSV(Grid: TZJGrid; const FileName: string ); overload;
var
Stream: TFileStream;
begin
Stream : = TFileStream.Create(FileName, fmOpenRead);
try
LoadGridFromCSV(Grid, Stream, Point(Grid.FixedColCount, Grid.FixedRowCount));
finally
Stream.Free;
end;
end;
function EncodeStr( const s: string ): string ;
var
I, k: Integer;
begin
I : = Pos( ' " ' , s);
if I <> 0 then
begin
Result : = Copy(s, 1 , I) + ' " ' ;
Inc(I);
while I < Length(S) do
begin
k : = I;
I : = PosEx( ' " ' , s, I);
if I = 0 then
begin
Result : = Result + Copy(s, k, Length(s) - k + 1 );
Break;
end
else
begin
Result : = Result + Copy(s, k, I - k + 1 ) + ' " ' ;
Inc(I);
end;
end;
Result : = ' " ' + Result + ' " ' ;
end
else if Pos( ' , ' , s) <> 0 then
Result : = ' " ' + s + ' " '
else
Result : = s;
end;
var
iRow, iCol: Integer;
Text: string ;
begin
for iRow : = ABounds.Top to ABounds.Bottom do
begin
for iCol : = ABounds.Left to ABounds.Right do
begin
Text : = EncodeStr(Grid.Cells[iCol, iRow].Text);
if iCol <> ABounds.Right then
Text : = Text + ' , ' ;
Stream.Write(Text[ 1 ], Length(Text));
end;
Text : = # 13 # 10 ;
Stream.Write(Text[ 1 ], Length(Text));
end;
end;
procedure SaveGridToCSV(Grid: TZjGrid; const FileName: string ); overload;
var
Stream: TStream;
begin
Stream : = TFileStream.Create(FileName, fmCreate);
try
SaveGridToCSV(Grid, Stream, Rect(Grid.FixedColCount, Grid.FixedRowCount,
Grid.ColCount - 1 , Grid.RowCount - 1 ));
finally
Stream.Free;
end;
end;
// 从流中加载
procedure LoadGridFromCSV(Grid: TZJGrid; Stream: TStream; DestCoord: TPoint); overload;
var
s: string ;
sLen: Integer;
newLine: Boolean;
function FetchText(var I: Integer): string ;
var
k: Integer;
bQuote: Boolean;
begin
bQuote : = False;
newLine : = False;
k : = I;
while k <= Length(s) do
begin
if (s[k] = ' , ' ) and not bQuote then
begin
Result : = Copy(s, I, k - I);
I : = k + 1 ;
Exit;
end
else if (s[k] = ' " ' ) then
begin
if (k < Length(s)) and (s[k + 1 ] = ' " ' ) then
Inc(k, 2 )
else
begin
bQuote : = not bQuote;
Inc(k);
end;
end
else if (s[k] = # 13 ) and (k < Length(s)) and (s[k + 1 ] = # 10 ) then
begin
Result : = Copy(s, I, k - I);
newLine : = True;
I : = k + 2 ;
Exit;
end
else
Inc(k);
end;
Result : = Copy(s, I, k - I);
end;
var
I: Integer;
Text: string ;
iRow, iCol: Integer;
begin
sLen : = Stream.Size - Stream.Position;
Grid.Clear;
if sLen = 0 then Exit;
SetLength(s, sLen);
Stream.Read(s[ 1 ], sLen);
I : = 1 ;
iRow : = DestCoord.Y;
iCol : = DestCoord.X;
Grid.BeginUpdate;
try
while I <= Length(s) do
begin
Text : = FetchText(I);
if Text <> '' then
Grid.Cells[iCol, iRow].Text : = Text;
if newLine then
begin
Inc(iRow);
iCol : = DestCoord.X;
end
else
Inc(iCol);
end;
finally
Grid.EndUpdate;
end;
end;
// 从文件中加载
procedure LoadGridFromCSV(Grid: TZJGrid; const FileName: string ); overload;
var
Stream: TFileStream;
begin
Stream : = TFileStream.Create(FileName, fmOpenRead);
try
LoadGridFromCSV(Grid, Stream, Point(Grid.FixedColCount, Grid.FixedRowCount));
finally
Stream.Free;
end;
end;