现有一个困扰我半年的问题,请一定帮忙解决,我想将一个文本文件导入到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
[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
解决方案 »
- 怎么控制delphi里的控件随窗口的大小而改变大小啊?
- 我现在想实现如下目的,请帮忙出出主意如何实现好。多客户端相互交换数据
- 请帮我诊断SQL语句(相同记录汇总出错)
- 如何适时的检查输入的字符是数字?
- 如何改变headercontrol的颜色?????????/能解决吗 高手!!!!!!!!!
- 数据库问题?
- 急问SQL语句,在线等待.........
- 如何在delphi中判断sql server运行情况?
- COM组件接口函数中能不能返回自己定义的类呢?
- ActiveForm的发布
- 请问:怎么样在服务器端强制关掉一个远程数据模块?
- 短消息采用PDU模式发送,为什么总有部分字节数据对方接收不到(最后几个字节丢失)?
我发现在导入文件前将删除原来的所有记录,如果要批量导入,该如何做,谢谢?
另:
关于Schema.ini,能讲的更详细点吗?给你单独加100分!
用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;
Schema.ini配置文件已设置,如何应用?
今天我又看到了一些新的方法,非常感激,谢谢!
我在网上下载的一个文本,将它导入数据库,很快的;我把我写的存储过程给你作个参考: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='数据导入成功!'
我的意思是:如何用Delphi调用?
{ 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 型值,用于标识代码页的字符集。
按照你的方法做(Delphi),提示“文本文件规范‘Schema.ini’不存在”。
请问如何设置SpecificationName。谢谢!!!
至于Schema.ini的格式,请参考上面的文字。
我已经建立Schema.ini文件,并指定了全路径,但还提示“文本文件规范‘Schema.ini’不存在”。我看好像是SpecificationName的问题,请问如何设置SpecificationName。谢谢!!!
例如: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.....
另外用以上例子编译时,提示EmptyParam未定义。
还请Kingron解答,非常感谢!!!
http://kingron.myetang.com/temp/importaccess.rar用Schema的方法不知道为什么总是不能通过,迷惑中……
1.只能导入第一列的数据。
2.ColNameHeader=True或False好象不起作用。
3.固定长度的数据头如何设置。(怎样设置都把整行当作一个字段名)
能否给个固定长度导入的demo?
再次感谢Kingron!!!