我在将CSV加载到StringGrid中时遇到了问题。有时候,它会耗尽内存,而且似乎每个值后面都有空白列。我还没有真正从CSV中读取数据,而不是输出到CSV中,所以我在线获取了一个股票示例,并根据需要对其进行了修改。
这是我目前得到的:
procedure x.LoadCSVtoGrid(ACSVFile : String; AStringGrid: TStringGrid)
var
LRowIndex, LColIndex: Integer;
LStrLine: string;
LFile: TStringList;
begin
AStringGrid.RowCount := 0;
AStringGrid.ColCount := 0;
if not FileExists(ACSVFile) then
exit;
LFile := TStringList.Create;
try
LFile.LoadFromFile(ACSVFile);
if LFile.Count = 0 then
exit;
AStringGrid.ColCount := Max(AStringGrid.ColCount, WordCount(LFile[0], [',', '"'], '"'));
AStringGrid.RowCount := LFile.Count;
for LRowIndex := 0 to LFile.Count - 1 do
begin
LStrLine := LFile[LRowIndex];
LColIndex := 0;
while LStrLine <> '' do
begin
if Pos('"', LStrLine) = 1 then
begin
Delete(LStrLine, 1, 1);
AStringGrid.Cells[LColIndex, LRowIndex] := Copy(LStrLine, 1, Pos('"', LStrLine) - 1);
Delete(LStrLine, 1, Pos('"', LStrLine));
end
else
begin
AStringGrid.Cells[LColIndex, LRowIndex] := Copy(LStrLine, 1, Pos(',', LStrLine) - 1);
Delete(LStrLine, 1, Pos(',', LStrLine));
end;
Inc(LColIndex);
end;
end;
finally
LFile.Free;
end;
对于较小的CSV文件,它做得很好。我想它以前阅读250-300行。它现在要处理的一些文件是500+。
老实说,在CSV导入到StringGrid之前,我不会对它的数据做太多的处理,但是一旦它进入StringGrid,它就被验证了。我必须确保语音标记中的逗号,即"text, here"
,被忽略,因为它是值的一部分。同样,这看起来很好地处理了阅读。
另一个我认为我可能会遇到的问题是AStringGrid.RowCount := LFile.Count;
,因为一些CSV文件有空行。如果有办法处理这个问题,我很乐意接受建议。
有几个版本的CSV文件,它应该能够读取,即计算列计数等。代码WordCount:
function x.WordCount(const S: string; const WordDelims: TSysCharSet; const QuoteChar: Char) : Integer;
var
LInWord: Boolean;
LQuoteOpen: Boolean;
i: Integer;
begin
Result := 0;
LInWord := False;
LQuoteOpen := False;
for i := 1 to Length(S) do
begin
if S[i] in WordDelims then
begin
if not LInWord or LQuoteOpen then
LInWord := False
else
begin
LInWord := True;
Inc(Result);
end;
end
else
begin
if S[i] = QuoteChar then
LQuoteOpen := not LQuoteOpen;
LInWord := True;
end;
end;
if LInWord and (not LQuoteOpen) then
Inc(Result);
我尝试了多个文件,大多数情况下,这个问题只发生在包含更多内容的较大CSV文件中。我尝试了各种版本的CSV到StringGrid过程,以查看上面的示例是否存在一些固有的错误。该示例工作正常,但仅适用于较小的文件。
如果你需要更多的信息告诉我。
1条答案
按热度按时间gcuhipw91#
1.内存问题
首先创建一个
TStringList
,然后向其加载数据一米一米一x一米二米一x
因为要将整个文件加载到字符串列表中,所以需要这么多内存,另外还要在
TStringGrid
中保存同样多的数据。通过分块读取文件来减少内存需求,比如说,一次读取1000行,然后可以在将它们移动到字符串网格后将其丢弃。
OTOH,你的"内存不足"问题也可能是由你的代码中的错误引起的。我在运行你的未修改代码时,我的非常小的测试文件遇到了"内存不足"的错误。
1.代码问题
在我的测试中,我使用了一个简单的文件,其中包含几条记录和一个位于不同位置的带引号的字段。
通过调用
WordCount()
函数(将字符串列表中的第一个字符串传递给该函数),可以确定TStringGrid
中所需的列数。当我传入第一个测试字符串时,
WordCount
正确返回5然后,控制返回到
LoadCSVtoGrid()
,在赋值AStringGrid.ColCount
和RowCount
之后,for LRowIndex
循环开始用当前行的数据填充网格。Delete()
从LStrLine的开头删除到Pos(',', LStrLine)
。这对于项"一"、"二"、"三"和"四"是可以的,但对于"五"则不行,因为最后一项后面没有逗号。这是代码中的主要缺陷,因为它不会删除最后一项。相反,由于循环运行
while LString <> ''
,它只是继续递增LColIndex
在我的机器上,它在几分钟后停止,并出现内存不足错误。
下面是我对
WordCount
(重命名为WordCountNew
)函数的看法:然后执行
LoadCSVtoGrid
过程:我添加了
CommaPos
变量,以便更容易人工模拟字符串末尾的逗号。通过这些更改,测试文件将正确读入网格。