緒論
我們經常需要讀取並處理文字檔的資料,通常是用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)