现有一个困扰我半年的问题,请一定帮忙解决,我想将一个文本文件导入到ACCESS 2000数据库中去,文本的每行格式如下: 
[email protected],200120,14,6,0,1,4,0,0,111,2,1,0,112,1188,113,113,52,0,0,37,37,18,14,2853,3077,4,3,0,0,0,3,3,0,0,0 
一般有一两万行。 
即以逗号分割,大约有30多个字段,数据库的表和字段与文本一样。 
我的方法是将文本读入字符串流,在一行行处理,用ADO操作,但速度很慢。一般一个2M的文本导入时间为5分钟。 有没有更好的方法来导入这样的文本文件,主要是加快速度,请指教。
原始帖子:
http://www.csdn.net/expert/topic/1019/1019825.xml?temp=.3394739

解决方案 »

  1.   

    如果可以不变成实现的话,你可以使用微软的DTS!!!
      

  2.   

    使用SQL导入文本文件~Select * Into 表 From [Text;Database=c:\abc\].a.txt会比你字串流处理快得多~
      

  3.   

    使用SQL导入文本文件到Access数据库,有一个Schema.ini配置文件控制格式,具体设置请查找JETSQL40.CHM中的帮助,"Text与Html"
      

  4.   

    To  fs_windy(飛龍) :
    我发现在导入文件前将删除原来的所有记录,如果要批量导入,该如何做,谢谢?
    另:
    关于Schema.ini,能讲的更详细点吗?给你单独加100分!
      

  5.   

    转载:
    用Delphi实现将纯文本资料转入数据库
    p>  在我们日常工作中,常会碰到这样一个难题:一大堆收集好的纯文本格式,比较规整的资料怎样才能将它们分离,转到自己已经建好的数据库中进行管理呢?
      例如,有一段人事档案资料archive.txt,内容如下: 
    小许 男 21 工程师 
    小吴 女 23 助理工程师 
    小蔡 男 22 助理工程师 
    小牟 女 22 工程师 
      要将它转入数据库archive.dbf中,archive.dbf结构如下:
      姓名,性别,年龄,职称
      怎么办呢?现在通过使用delphi编程,很好地解决了这个难题。Delphi提供了许多功能强大,丰富的字符处理函数和过程,常用的有:
      (1)function Length(S:String):Integer返回串的长度
      (2)function Copy(S:String;Index,Count:Integer):String 给出一个字符串中串的拷贝
      (3)function Pos(Substr:String;S:String);Integer 查找子串在字符串中的位置
      (4)Procedure Delete(VarS:String;Index,Count:Integer);从一个字符串中去除子串
      利用Delphi提供的已有函数和过程基础上编制自己的三个函数,实现了纯文本格式资料转入数据库功能。只要Delphi支持的数据库都可以支持。
      archive.txt中每行数据为一个字符串,字符串中每个被分割的数据为一个字段,分割每个字段的字符为分割符,这里是空格,也可以是,、;、#等符号。具体思想是:先将字符串进行调整,然后把串中每个字符同分割符比较,将不是分割符的字符追加到MyStr串中,最后得到一个字段的内容。通过一个循环,就可以将一个字符串分成几个字段。
      Function Regulate(aString,Sepchar:string):string 去掉多余的分割符,规范字符串
      Function GetSubStr(varsSt g:string;SepChar:String):String;得到字符串中一个子串,因要改变参数aString的值,所以将它用var定义。
      FunctionGetSubStrNum(aString,SepChar:String):Integer;计算一个字符串要被分割成几个字段。
      参数:aString是所需分割的一个字符串,SepChar是分割符。  Function RegulateStr(aString:String;Sepchar:String):String; 
      var
      i,Num:Integer;
      Flag:Boolean;
      MyStr,TempStr:String;
      begin
      Flag:=False;进行标志,去除多余的分割符
      Num:=Length(aString); 计算aString串的长度
      for i:=1 to Num do
      begin
      TempStr:=Copy(aString,i,1);取aString串中的一字符
      if TempStr SepChar then
      begin
      MyStr:=MyStr+TempStr;
      Flag:=True;
      end
      else
      if(Flag = True)then
      begin
      Mystr:=Mystr+TempSrt;
      Flag:=False;
      end;
      end;
      if MyStr[Length(MyStr)] SepChar then
      MyStr:=MyStr+SepChar;
      RegulateSrt:=MyStr;
      end;  Function GetSubStr(var aString:String,SepChar:Strign):String;
      var
      Mysrt:String;
      StrLen:Integer;
      SepCharPso:Integer;
      begin
      StrLen:=Length(aString);
      SepCharPos:=Pos(SepChar,aString);计算分割符在子串中的位置
      MyStr:=Copy(aString,1,SepCharPos-1); 将分割符前所有字符放到mystr串中
      Delete(aString,1,SepCharPos);除去分割符和分割符前的子串
      GetSubStr:=MyStr;返回一个字段
      end;  FunctionTforml.GetSubStrNum(aString:String;SepChar:String):Integer;
      var
      i:Integer;
      StrLen:Integer;
     Num:Integer;
      begin
      StrLen:=Length(aString);
      Num:=0;
      for i:=1 to StrLen do
      if Copy(aString,i,1) = SepCharthen
      Num:=Num+1;
      GetSubSrtNum:=Num;
      end;  有了上面三个函数,现在介绍一下具体的应用:
      1.首先建立一个窗体Forml,加入一个RichEditl(或Menol),一个按钮Buttonl和一个Tablel,设置Tablel的属性:
      Tablell.DataBase = c:\Archivs
      Tablell.TableName =Archive.dbf  2.分别加入以下程序:
      Const Space= 
      ProcedureTForml.FormCreate(Sender:Tobject);
      begin
      RichRditl.Lines.LoadFromFile(Archive.txt);
      end;  ProcedureTForml.Button1Click(Sender:Tobject);
      var
      i,j:Integer;
     MyLine:String;
      begin
      with Tablel do
      begin
       Open;
     for i:=0 to RichEditl.Lines.Count-1 do
     begin
      MyLine:=RegulateStr(Richeditl.Lines[i],Space);
      for j:=1 to Num do 
      begin
      Append;
      fileds[j-1].aString:=GetSubSrt(MyLine,Space));
      post;
      end;
      end;
      end;
      end;
      

  6.   

    To  fs_windy(飛龍) :
      Schema.ini配置文件已设置,如何应用?
      

  7.   

    我觉得把文本导入到RichText类似的控件中,然后利用循环操作就快多了。
    今天我又看到了一些新的方法,非常感激,谢谢!
      

  8.   

    到这里看看http://kingron.myetang.com/document/delphi/access_3.html未经许可我不能转载过来,楼主自己看看吧
      

  9.   

    用SQL的BULK INSERT命令操作:
    我在网上下载的一个文本,将它导入数据库,很快的;我把我写的存储过程给你作个参考:CREATE PROCEDURE Proc_TxtToTable
    @dataPath varchar(1000)='D:\test.txt'AS
    declare @ws_sql varchar(1000)
    set @ws_sql='BULK INSERT tStock_table FROM '''+rTrim(@dataPath)+''''
    set @WS_sql=@ws_sql+' WITH (DATAFILETYPE = '''+'char'+''', FIELDTERMINATOR = '''+','+''')'
    exec(@ws_sql)
    if @@error<>0
    select Msg='数据导入出错!'
    else 
    select Msg='数据导入成功!'
      

  10.   

    to bluemeteor(挂月||╭∩╮(︶︿︶)╭∩╮) :
        我的意思是:如何用Delphi调用?
      

  11.   

    导入文本数据到Access的时候如何指定字段信息{ Kingron版权所有,未经授权不得转载 }
    { Copyright 2002.11.28 Kingron, All right reserved }
    参考MSDN帮助主题:
    ACC2000: Error When You Try to Use Schema.ini to Import or Export with the TransferText Method
    TransferText在导入数据的时候,有的时候,Access会把一些数据作为数值型的数据,实际上,我们需要作为字符型的数据,那么如何在导入的时候,指定导入的各种规格和细节呢?答案是利用Schema.ini即可(导入/导出规格文件)。
    有几种方式创建Schema,第一种是利用Access自身的文本数据导入导出向导:
     
    在这个对话框中,点击[高级...]按钮,弹出对话框:
     
    然后只要设定好各种格式,然后点击[另存为]保存即可。这种方式创建的Schema,只能集成在数据库中,无法灵活单独使用,因此我们需要用到另外一种方式:INI文件,推荐使用INI文件这种方式。Schema.ini格式如下(参考:MSDN主题 Schema.ini File):
    Schema.ini用于提供文本数据中的记录规格信息。每个Schema.ini的条目用于指明表的5个特征之一:
    文本文件名
    文件名有方括号括起来,例如如果要对Sample.txt使用Schema,那么它的对应的Schema条目应该是
    [Sample.txt]
    文件格式
    指令如下:
    Format=Value
    Value可以取下面的值之一:
    TabDelimited   用Tab分隔
    CSVDelimited   用逗号分隔
    FixedLength    固定长度
    Delimited(C)   指定字符,其中C可以为除了双引号(")外的任何字符,也可以为空
    字段名、字段宽度和类型
    格式为:Coln=字段名 数据类型 [width 宽度]
    字段名可以是任意字符,如果字段名包含空格,请使用双引号括起来。
    数据类型可以为:
    Bit
    Byte
    Short(Integer)
    Long
    Currency
    Single
    Double(Float)
    DateTime(Date DateFormat)
    Text(Char)
    Memo(LongChar)
    其中DateFormat是日期的格式字符串例如:Date YYYY-MM-DD
    字符集
    格式:CharacterSet=ANSI | OEM
    格式只有两种:ANSI和OEM
    特殊数据类型转换
    特殊数据类型转换一般使用的比较少,主要是自定义日期、货币等等的数据格式,一般不用理会。在此也不作详细叙述。请自己查看MSDN帮助:Schema.ini File下面给出一个简单的例子,假设有一个表Contacts.txt类似下面:
    First     NameLast NameHireDate
    Nancy     Davolio  10-22-91
    Robert    King     10-23-91 那么Schema.ini个是类似下面的INI文件(我加了注释):
    [Contacts.txt]  ///需要导入的文本文件名
    ColNameHeader=True  ///是否有数据头
    Format=FixedLength  ///字段固定长度
    MaxScanRows=0   ///最多导入行
    CharacterSet=OEM   ///字符集
    Col1="First Name" Char Width 10   ///第一列格式
    Col2="Last Name" Char Width 9   ///第二列格式
    Col3="HireDate" Date Width 8    ///第三列格式
    ////依此类推我们可以根据数据自动创建这个Schema.ini文件!
    注意,Schema.ini必须和需要导入的文本文件在同一目录!!!如果不在同一个目录,必须指定Schema.ini的全路径!
    此后,我们就可以利用下面的语句来导入数据了:
    DoCmd.TransferText acImportFixed, , "Contacts", "C:\My Documents\Contacts.txt"
    或者
    DoCmd.TransferText acImportFixed, "C:\My Documents\Schema.ini", "Contacts", "C:\My Documents\Contacts.txt"
    翻译成Delphi的代码就是:function ImportDataToAccess(AccDB,Table,Txt:string;Schema:string=''):Boolean;
    var
      AccessApp:Variant;
    begin
      AccessApp := CreateOleObject('Access.Application');
      AccessApp.OpenCurrentDatabase(AccDB);
      AccessApp.DoCmd.TransferText(acImportFixed,Schema,Table,Txt);
      VarClear(AccessApp);
    end;下面给出TransferText的语法(摘自Access帮助):
    DoCmd.TransferText [TransferType][, SpecificationName], TableName, FileName[, HasFieldNames][, HtmlTableName][, CodePage]TransferType  可选 AcTextTransferType。AcTextTransferType 可以是下列 AcTextTransferType 常量之一: 
    acExportDelim 
    acExportFixed 
    acExportHTML 
    acExportMerge 
    acImportDelim 默认 
    acImportFixed 
    acImportHTML 
    acLinkDelim 
    acLinkFixed 
    acLinkHTML 
    如果将该参数留空,则采用默认常量 (acImportDelim)。SpecificationName  可选 Variant 型。字符串表达式,表示在当前数据库中创建并保存的导入或导出规格的名称。对于固定长度的文本文件, 必须指定参数或使用 schema.ini 文件,该文件还必须保存在导入、链接或导出的文本文件的同一个文件夹中。若要创建一个方案文件, 可使用文本导入/导出向导创建此文件。对于分隔的文本文件和 Microsoft Word 邮件合并数据文件,可以将该参数留空,以便选择默认的导入/导出规格。TableName  可选 Variant 型。字符串表达式,表示要向其导入文本数据、从中导出文本数据或链接文本数据的 Microsoft Access 表的名称,或者要将其结果导出到文本文件的 Microsoft Access 查询的名称。FileName  可选 Variant 型。字符串表达式,表示要从中导入、导出到或链接到的文本文件的完整名称(包括路径)。HasFieldNames  可选 Variant 型。使用 True (-1) 可以在导入、导出或链接时,使用文本文件中的第一行作为字段名。使用 False (0) 可以将文本文件中的第一行看成普通数据。如果将该参数留空,则采用默认值 (False)。该参数将被 Microsoft Word 邮件合并数据文件忽略,这些文件的第一行中必须包含字段名。HTMLTableNam  可选 Variant 型。字符串表达式,表示要导入或链接的 HTML 文件中的表或列表的名称。除非 transfertype 参数设为 acImportHTML 或 acLinkHTML,否则该参数将被忽略。如果将该参数留空,则导入或链接 HTML 文件中的第一个表或列表。如果 HTML 文件中存在 <CAPTION> 标记,则 HTML 文件的表或列表名称取决于该标记指定的文本。如果没有 <CAPTION> 标记,则名称由 <TITLE> 标记指定的文本决定。如果有多个表或列表具有相同的名称,则 Microsoft Access 将通过给每个表或列表名称结尾添加一个数字,如“雇员1”和“雇员2”来区分它们。CodePage  可选 Variant 型。Long 型值,用于标识代码页的字符集。
      

  12.   

    to Kingron:
       按照你的方法做(Delphi),提示“文本文件规范‘Schema.ini’不存在”。
    请问如何设置SpecificationName。谢谢!!!
      

  13.   

    晕倒,Schema.ini文件需要你自己建立,如果没有,就用空的,修改一下代码吧。
    至于Schema.ini的格式,请参考上面的文字。
      

  14.   

    如果没有Schema.ini,请使用EmptyParam代替即可。
      

  15.   

    to Kingron:
       我已经建立Schema.ini文件,并指定了全路径,但还提示“文本文件规范‘Schema.ini’不存在”。我看好像是SpecificationName的问题,请问如何设置SpecificationName。谢谢!!!
      

  16.   

    需要把Schema的文件名中的\用\\代替:
    例如:C:\Demo\Schema.ini--〉  C:\\Demo\\Schema.ini你的要求直接用:
    function ImportDataToAccess(AccDB,Table,Txt:string):Boolean;
    var
      AccessApp:Variant;
    begin
      AccessApp := CreateOleObject('Access.Application');
      AccessApp.OpenCurrentDatabase(AccDB);
      AccessApp.DoCmd.TransferText(acImportDelim, EmptyParam,Table,Txt,-1);
      VarClear(AccessApp);
    end;procedure TForm1.Button1Click(Sender: TObject);
    var
      ExePath:string;
    begin
      ExePath :=IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0)));
      ImportDataToAccess(ExePath+'Demo.mdb','Demo',ExePath+'demo.txt');
    end;注意,你的Text第一行必须有FieldName定义信息。如果没有,请使用新的TableName,否则你的字段定义名必须为F1,F2,F3.....
      

  17.   

    已经把Schema的文件名中的\用\\代替,但还提示“文本文件规范‘Schema.ini’不存在”。我希望在程序中指定Schema.ini的路径。
       另外用以上例子编译时,提示EmptyParam未定义。
       还请Kingron解答,非常感谢!!!
      

  18.   

    一个Demo:
    http://kingron.myetang.com/temp/importaccess.rar用Schema的方法不知道为什么总是不能通过,迷惑中……
      

  19.   

    非常感谢Kingron!!!不定长度的导入已经搞定了。但固定长度的导入还有一点问题。
    1.只能导入第一列的数据。
    2.ColNameHeader=True或False好象不起作用。
    3.固定长度的数据头如何设置。(怎样设置都把整行当作一个字段名)
        能否给个固定长度导入的demo?
    再次感谢Kingron!!!
      

  20.   

    使用DTS是一个比较快的方法。