SQL表使用BCP进行delphi记录

时间:2011-12-20 08:26:55

标签: sql delphi bcp

我有一个场景,我必须从sql表中导出大约500,000条记录的数据,以便在Delphi应用程序中使用。数据将被加载到打包记录中。有没有一种方法可以使用BCP写入类似于将记录写入文件的数据文件。

截至目前,我正在使用此psudo代码加载数据。

    // Assign the data file generated from BCP to the TextFile object.
    AssignFile(losDataFile, loslFileName);
    Reset(losDataFile);
    while not EOD(losDataFile) do
    begin
      // Read from the data file until we encounter the End of File
      ReadLn(losDataFile, loslDataString);

      // Use the string list comma text to strip the fields
      loclTempSlist.CommaText := loslDataString;

      // Load the record from the items of the string list.
      DummyRec.Name := loclTempSList[0];
      DummyRec.Mapped = loclTempSList[1] = 'Y';
    end;

为方便起见,我在下面列出了Dummy rec的类型

    TDummyRec = packed record
      Name : string[255];
      Mapped : Boolean;
    end;

所以,我的问题是,不是将数据导出到文本文件,而是可以将数据导出为二进制文件,以便我可以使用记录类型直接从文件中读取数据吗?

   loclFileStream := TFileStream.Create('xxxxxx.dat', fmOpenRead or fmShareDenyNone);
   while loclFileStream.Position < loclFileStream.Size do
   begin
     // Read from the binary file
     loclFileStream.Read(losDummyData, SizeOf(TDummyRec));
     //-  -------- Do wat ever i want.
   end;

我没有太多使用BCP的经验。请帮帮我。

由于 终止子...

2 个答案:

答案 0 :(得分:1)

在您的记录中,string[255]将创建固定大小的Ansi字符串(即所谓的shortstring)。此类型明显已弃用,不应在您的代码中使用。

使用TFileStream(即使它会起作用)直接保存它将是一个非常浪费的空间。每个记录将为每个名称存储256个字节。

使用string[255](即所谓的shortstring)会对字符串进行隐藏转换,以便对其进行大多数访问。所以这不是最好的选择,恕我直言。

我的建议是使用我们的开源类use a dynamic array then serialize / unserialize it。对于您的存储,您可以使用动态数组。适用于Delphi 5至XE2。并且您将能够在记录中使用string

TDummyRec = packed record
  Name : string; // native Delphi string (no shortstring)
  Mapped : Boolean;
end;

OP评论后编辑:

BCP只是一个命令行工具,用于将导出很多行导入一个SQL表。因此,恕我直言BCP不适合您的目的。

您似乎需要 SQL表中导入

在这种情况下:

  • 使用shortstring在任何情况下都会浪费内存,因此与使用优质string相比,内存更快;
  • 您可以尝试我们的开源类逐个检索所有数据行,然后使用此数据填充您的记录:请参阅SynDB classes - 它比ADO轻;然后,您将能够逐个检索记录数据,然后使用我们的记录序列化函数来创建一些二进制内容 - 或者尝试使用像SynBigTable这样的专用更快的引擎;
  • 有些文章关于直接使用BCP从Delphi代码in here - it is in french, but you can use google to translate ithere for fast bulk copy使用的OleDB特性;包含完整的源代码。

答案 1 :(得分:0)

你想把一个SQL表读入一个记录,我不知道你为什么要使用古老的AssignFile。

您应该为您的数据库使用TADOQuery(或合适的变体) 在其中放置一个合理的SQL查询;类似的东西:

SELECT field1, field2, field3 FROM tablename WHERE .....

如有疑问,可以使用:

SELECT * FROM tablename

将从表格中选择所有字段。

以下代码将遍历所有记录和所有字段,并将它们保存在变体中并将其保存在FileStream中。

function NewFile(Filename: string): TFileStream;
begin
  Result:= TFileStream.Create(Filename, fmOpenWrite);
end;

function SaveQueryToFileStream(AFile: TFileStream; AQuery: TADOQuery): boolean;
const
  Success = true;
  Failure = false;
  UniqueFilePrefix = 'MyCustomFileTypeId';
  BufSize = 4096;
var
  Value: variant;
  Writer: TWriter;
  FieldCount: integer;
  c: integer;
  RowCount: integer;
begin
  Result:= Success;
  try
    if not(AQuery.Active) then AQuery.Open

    FieldCount:= AQuery.Fields.Count;
    Writer:= TWriter.Create(AFile, BufSize);
    try
      Writer.WriteString(UniqueFilePrefix)
      //Write the record info first
      Writer.WriteInteger(FieldCount);
      //Write the number of rows
      RowCount:= AQuery.RecordCount;
      WriteInteger(RowCount);
      AQuery.First;
      while not(AQuery.eof) do begin
        for c:= 0 to FieldCount -1 do begin
          Value:= AQuery.Fields[c].Value;
          Writer.WriteVariant(Value);
        end; {for c}
        AQuery.Next;
      end; {while}
    except 
      Result:= failure;
    end;
  finally
    Writer.Free;
  end;
end;