首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Delphi7处理超大文本文件数据的最佳解决方案

Delphi7处理超大文本文件数据的最佳解决方案
EN

Stack Overflow用户
提问于 2013-07-18 09:01:43
回答 6查看 10.2K关注 0票数 2

我有这样的文本文件:

代码语言:javascript
复制
"01","AAA","AAAAA" 
"02","BBB","BBBBB","BBBBBBBB" 
"03","CCC" 
"04","DDD","DDDDD"

我想把这个文本文件数据加载到sybase db的临时表中。因此,我需要构建一个程序来逐行读取这个文本文件,直到eof。如果文本文件较小,则逐行读取的过程较快。但是如果文本文件太大(可能超过500M),逐行读取的过程就会太慢。我认为逐行读取的方法不适合大型文本文件。因此,需要寻找其他解决方案,将文本文件数据加载到数据库中,而不是逐行读取文本文件。有什么建议吗?示例代码:

代码语言:javascript
复制
var
  myFile : TextFile;
  text   : string;

begin
  // Try to open the Test.txt file for writing to
  AssignFile(myFile, 'Test.txt');

  // Display the file contents
  while not Eof(myFile) do
  begin
    ReadLn(myFile, text);
    TempTable.append;
    TempTable.FieldByName('Field1').asstring=Copy(text,2,2);
    TempTable.FieldByName('Field2').asstring=Copy(text,7,3);
    TempTable.FieldByName('Field3').asstring=Copy(text,13,5);
    TempTable.FieldByName('Field4').asstring=Copy(text,21,8);
    TempTable.post;
  end;

  // Close the file for the last time
  CloseFile(myFile);
end;
EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2013-07-18 14:00:36

一些一般提示:

  • 确保你的TempTable在内存中,或使用快速的数据库引擎-看看SQlite3或其他方法(如FireBird embedded,NexusDB或ElevateDB)作为可能的数据库alternatives;
  • If你不使用一个Transaction;
  • For,但一个真正的数据库,确保你嵌套在一个TTable一个真正的数据库,检查如果你不能使用ArrayDML功能,这是更快的插入大量数据,因为你想在一个远程数据库(如Sybase) - such Array DML is handled for instance with AFAIK;
  • FieldByName('...')方法众所周知非常慢:使用本地变量TField变量使用TextFile,分配更大的临时缓冲区;
  • 如果您正在使用较新的Unicode版本的Delphi (2009+),使用TextFile不是最佳选择。

所以你的代码可能是:

代码语言:javascript
复制
var
  myFile : TextFile;
  myFileBuffer: array[word] of byte;
  text   : string;
  Field1, Field2, Field3, Field4: TField;
begin

  // Set Field* local variables for speed within the main loop
  Field1 := TempTable.FieldByName('Field1');
  Field2 := TempTable.FieldByName('Field2');
  Field3 := TempTable.FieldByName('Field3');
  Field4 := TempTable.FieldByName('Field4');

  // Try to open the Test.txt file for writing to
  AssignFile(myFile, 'Test.txt');
  SetTextBuf(myFile, myFileBuffer); // use 64 KB read buffer

  // Display the file contents
  while not Eof(myFile) do
  begin
    ReadLn(myFile, text);
    TempTable.append;
    Field1.asInteger := StrToInt(Copy(text,2,2));
    Field2.asString := Copy(text,7,3);
    Field3.asString := Copy(text,13,5);
    Field4.asString := Copy(text,21,8);
    TempTable.post;
  end;

  // Close the file for the last time
  CloseFile(myFile);
end;

您可以使用嵌入式引擎实现非常高的速度,几乎没有大小限制,但您的存储空间。例如,请参阅how fast we can add content to a database in our ORM:数据库文件中每秒大约130,000 / 150,000行,包括所有ORM编组。我还发现SQLite3生成的数据库文件比其他方法小得多。如果您希望快速检索任何字段,请不要忘记在插入行数据后在数据库中定义INDEXes (为了提高速度)。对于SQLite3,已经有一个ID/RowID整数主键可用,我想它映射了您的第一个数据字段。SQLite3已对此ID/RowID整数主键进行了索引。顺便说一下,我们的对象关系映射现在支持FireDAC / AnyDAC and its advanced Array DML feature

票数 4
EN

Stack Overflow用户

发布于 2013-07-18 12:07:35

文本文件通常有一个非常小的缓冲区。考虑使用SetTextBuf function来提高您的性能。

代码语言:javascript
复制
var
  myFile : TextFile;
  text   : string;
  myFileBuffer: Array[1..32768] of byte;
begin
// Try to open the Test.txt file for writing to
  AssignFile(myFile, 'Test.txt');
  SetTextBuf(MyFile, myFileBuffer);
  Reset(MyFile);

// Display the file contents
  while not Eof(myFile) do
    begin
      ReadLn(myFile, text);
    end;

// Close the file for the last time
  CloseFile(myFile);
end;
票数 4
EN

Stack Overflow用户

发布于 2013-07-18 16:24:17

除了前面提到的内容之外,我还会避免使用任何TTable组件。您最好使用TQuery类型的组件(取决于您正在使用的接入层)。就像这样:

代码语言:javascript
复制
qryImport.SQL := 'Insert Into MyTable Values (:Field1, :Field2, :Field3, :Field4);';

Procedure ImportRecord(Const pField1, pField2, pField3, pField4 : String);
Begin
  qryImport.Close;
  qryImport.Params[0].AsString := pField1;      
  qryImport.Params[1].AsString := pField2;`
  qryImport.Params[2].AsString := pField3;
  qryImport.Params[3].AsString := pField4;
  qryImport.ExecSQL;
End;

希望这能有所帮助。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17712813

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档