绪论
我们经常需要读取并处理文本文件的数据,通常是用StreamReader (.NET) / FileSystemObject (VB 6.0)逐行读取.
假如我们可以像查询数据库的表一样读取文件并处理数据,我们会发现上面的方法有一些劣势.
一些劣势是:
  1.保持连接环境.一直锁住文件直到处理完毕.
  2.需要分隔每一行以得到部分列的数据.某些行的数据要是包含逗号处理起来就比较困难了.Example: “Yes, comma is here”,2,”Hello, another comma”,4,5,6
  3.在读完数据开始处理之前我们没有筛选数据的选项.
  4.要统计文件的记录条数或者统计包含特别类型的记录条数需要读完整个文件.
我们可以列举出更多的劣势.相对逐行读取的劣势而言使用数据库的表查询更有价值.
我们可以像读取一个数据库表一样读取文本文件吗?
如果答案是否定的也就没有这篇讨论的文章了.是的,我们可以像读取数据库表一样读取文件并且可以轻松克服前面提及的劣势.
读取数据
连接一个数据库并从表里查询数据是比较简单的.既然这样,我们就将文本文件当作表,将文件所在的目录当作数据库.
读取数据的步骤:
  1.打开数据库连接
  Note:这里的连接字符串很重要.它因我们要读的文件类型而有所不同.我们将在本文后面讨论.
  2.使用基础查询语言获取结果集.
  3.遍历结果集以读取字段.
 C# Code:
DataSet myData = new DataSet();
string myXML;
string strFilePath = "C:\\";
string mySelectQuery = "SELECT * FROM SampleFile.CSV";
OleDbConnection myConnection 
= new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\\;" + 
                                                
"Extended Properties=\"text;HDR=YES;FMT=Delimited\"");
OleDbDataAdapter dsCmd 
= new OleDbDataAdapter(mySelectQuery, myConnection);
//Fill the DataSet object
dsCmd.Fill(myData, "CustomerOwners");
//Create a XML document with the table data
myData.WriteXml("D:\\TestXML.xml");
myConnection.Close();
VB 6.0 code:
'Set the database connection
objConnection.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
                   
"Data Source=" & strFilePath & ";" & _
                   
"Extended Properties=""text;HDR=YES;FMT=Delimited"""

'Query from the file assuming it as a database table
objRecordset.Open "SELECT * FROM " & fileName, _
          objConnection, adOpenStatic, adLockOptimistic, adCmdText

'Loop through the records and insert in to the table
Do Until objRecordset.EOF
    Debug.Print objRecordset.Fields.Item(
"Number")
    Debug.Print objRecordset.Fields.Item(
"Name")
objRecordset.MoveNext
Loop
我们像读取数据库表一样读取文本文件.让我们来看看这种方法的优势:
  1.这种处理比较快
  2.首先要说明下它处理数据行并分离数据的的方式.假如你的文本的某一列包含里有一个逗号(上面列出的第2点劣势),程序将自动处理这种情况.我们不必处理这种个别情况.
  3.如果给定筛选标准我们可以查询出指定的记录行.
  4.现在看来,很显然,在查询的时候可以使用非常有用的WHERE,HAVING或者GROUP子句
     Ex: "SELECT Number, Count(Name) FROM SampleFile1.CSV GROUP BY Number HAVING Count(Name) >= 1"

  5.我们可以基于条件过滤数据,一次性获取文件里符合条件的全部数据.这些可以使用 RowFilter/Filter属性 或 DataView/RecordSe完成.如我曾说过的,一旦我们将数据读到 Dataset/RecordSet,我们可以使用它们完成所有的操作.包括筛选,排序等..
其他文件格式
我们讨论了读取使用逗号分隔的文件(CSV).那么如何使用这种方式处理TAB分隔的文件和固定长度的文件呢? 重点就是我们所提供的连接字符串。
让我们来看看连接字符串的具体内容:
Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\FolderName;Extended Properties="text;HDR=YES;FMT=Delimited"

Provider – 代表数据库类型.我们使用OLEDB连接类型.
Data Source – 文件夹被当作数据库.
Extended Properties – 这些属性说明我们将使用哪种方式读取文件.

字符串的第一部分定义了文件类型.尽管文件格式可以分类为逗号分割,TAB分割或者固定长度的数据,但他们都是简单文本.如果我们读取EXCEL文件则需要使用EXCEL X.X,X.X是EXCEL的版本号.

  • HDR (Header) – 用来指定header(文件头)是否是可用的.YES - 文件的第一行被当作文件头,其他行是数据. NO - 数据从第一行开始. FMT (Format) –指定格式类型.可以是下面的值:
    Delimited 数据以逗号分割的文件.逗号是默认的分割符.
    Delimited(x) 数据以'X'分割符分割的文件.
    TabDelimited 数据以TAB分割的文件.
    FixedLength 以指定的长度读取数据.你可以通过 Col1, Col2 等指定列长度和类型. More at MSDN.
如果指定的格式是'Delimited',那么默认值是逗号(,),这个值存储在注册表里.可以修改HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\Text\Format来改变默认设置.
不要随意修改注册表.对此MS提供了另一个可选的方法:提供我们一个Schema.ini文件.如果我们读取一个定长的文件,我们应当使用Schema.ini文件.在Schema.ini里定字段的长度.
读取多文件
如果要将同列的多文件和数据合并与筛选,我们可以像在SQL里一样处理.我们可以连接表以得到合并后的数据.需要注意的是输出的数据是CROSS JOIN所有的文件的行.请确保你筛选的数据是基于相同的列.
Example:
SampleFile1.CSV – (EmpID, Name, Address)
SampleFile2.CSV – (EmpID, Salary, Month)
//Where clause is used to get ‘Natural Join’
string mySelectQuery = "SELECT * FROM SampleFile.CSV As Sample1, SampleFile2.CSV As Sample2 " + 
                       
"Where Sample1.Number=Sample2.Number";
'Where clause is used to get ‘Natural Join’
objRecordset.Open "SELECT * FROM SampleFile.CSV As Sample1, SampleFile2.CSV As Sample2 " & _ 
                  
"Where Sample1.Number=Sample2.Number", _
                  objConnection, adOpenStatic, adLockOptimistic, adCmdText
别名(Sample1是SampleFile.CSV的别名)在JOIN查询里是必须的,尤其是当表有相同的列名时.在本列,表名(文件名)包含有点号(.),因此查询解析器将被表名里的点号误导,以致将‘CSV.Number’ 当作列名.
原文:Read text file (txt, csv, log, tab, fixed length)
posted on 2008-06-19 17:10  空空儿  阅读(2258)  评论(0编辑  收藏  举报