2015年4月7日 星期二

使用 CsvHelper - Part.3 其他操作說明

使用 CsvHelper 的讀寫操作在前兩篇都已經有說明了,如果需要更進階的操作說明,可以直接參考 CsvHelper 的文件檔或是直接到 Github Repository 裡面的單元測試專案裡去看,而這一篇則是再補上一些在處理 CSV 檔案讀寫時的方法操作說明。

使用 CsvHelper - Part.1 資料寫入
使用 CsvHelper - Part.2 資料讀取


Github - CsvHelper
https://github.com/JoshClose/CsvHelper

CsvHelper Documentation
http://joshclose.github.io/CsvHelper/

 

判斷 CSV 檔案是否存在以及是否有資料

判斷檔案是否存在,這只需要使用到 System.IO File 的 Exists 方法做處裡就可以,而如果檔案存在則要去判斷檔案內是否有資料,有些人的做法是先將 CSV 檔案的全部資料讀取之後再去做判斷,這個做法很直接,但如果碰到資料很多的時候,這方法就不是很好。

例如使用 CsvHelper 時,有些人會用以下的方式去判斷是否有資料的存在,先把 CSV 裡的全部資料取出來之後再去判斷是不是有資料,這方法當遇到 CSV 檔案裡有很多資料再加上有頻繁讀寫的狀況時,這做法就不是很適當,

image

可以改用以下的做法,一開始先去判斷檔案是否存在,如果檔案存在才去使用 CsvHelper 讀取檔案,這邊會使用到 CsvReader 的 IsRecordEmpty 方法,不過用這方法前要先執行 CsvReader 的 Read 方法,要先讓 CsvReader 讀檔案,這樣才能判斷 CSV 檔案內是否有資料,而單純的讀檔案而並沒有去「取出」檔案內的資料,這在效能上就會有很大的差別。

image

 

使用 Append 方式讓資料接續寫入 CSV 檔案

在第一篇介紹使用 CsvHelper 處理資料寫入的時候都是以查詢出來的全部資料寫入到 CSV 檔案裡,但如果是要將一筆資料接續在 CSV 檔案的最後面的話,這應該怎麼處理呢?

例如,我們已經將一筆資料寫入到 Foobar.csv 檔案裡,

image

如果是想用 CsvReader 的 WriteRecord 方法將資料寫入到 CSV 檔案的話,就會得到以下的結果,

image

image

如果要接續寫入既有的 CSV 檔案,在一開始的 StreamWriter 就需要做設定,

MSDN- StreamWriter 類別 (System.IO)
MSDN - StreamWriter 建構函式 (String, Boolean, Encoding) (System.IO)

“使用指定的編碼方式和預設緩衝區大小,為指定的檔案初始化 StreamWriter 類別的新執行個體。 如果檔案存在,可以將它寫入或附加。 如果檔案不存在,這個建構函式會建立新的檔案。”

“append: true 表示要附加資料至檔案,false 表示要覆寫檔案。 如果指定的檔案不存在,則這個參數沒有任何作用,而且建構函式會建立新的檔案。”

所以這邊就將寫入資料到 CSV 檔案的程式做了修改,並且配合上面所建立的 IsNotExistOrRecordEmpty 方法,這是要去判斷是否有無資料,如果沒有資料就需要在 CSV 的第一列寫入欄位名稱,如果已經資料存在就不需要去寫入欄位名稱。

image

public void WriteToCSV<T>(string file, T record)
{
    bool isNotExistsOrRecordEmpty = IsNotExistsOrRecordEmpty(file);
 
    using (var sw = new StreamWriter(file, true, Encoding.UTF8))
    using (var writer = new CsvWriter(sw))
    {    
        if(isExistsOrRecordEmpty)
        {
            writer.WriteHeader(typeof(T));
        }
        writer.WriteRecord(record);
    }
}
 
public bool IsNotExistsOrRecordEmpty(string file)
{
    if(!File.Exists(file))
    {
        return true;
    }
    using (var sr = new StreamReader(file))
    using (var reader = new CsvReader(sr))
    {
        reader.Read();
        return reader.IsRecordEmpty();
    }    
}

使用方式

image

輸出結果

image

image

將要輸入的資料內容做個修改然後再執行一次,

image

image

重新整理程式,完整的程式內容如下:

void Main()
{
    string fileName = @"z:\Foobar.csv";
 
    var record = new Foobar()
    { 
        ID = "111", 
        FirstName = "222", 
        LastName = "333", 
        Title = "444" 
    };
    
    WriteToCSV<Foobar>(fileName, record);    
    var records = ReadFromCSV<Foobar>(fileName);
    records.Dump();
}
 
public IEnumerable<T> ReadFromCSV<T>(string file)
{
    using (var sr = new StreamReader(file))
    using (var reader = new CsvReader(sr))
    {        
        var records = reader.GetRecords<T>();        
        return records.ToList();
    }
}
 
public void WriteToCSV<T>(string file, T record)
{
    bool isNotExistsOrRecordEmpty = IsNotExistsOrRecordEmpty(file);
 
    using (var sw = new StreamWriter(file, true, Encoding.UTF8))
    using (var writer = new CsvWriter(sw))
    {    
        if(isNotExistsOrRecordEmpty)
        {
            writer.WriteHeader(typeof(T));
        }
        writer.WriteRecord(record);
    }
}
 
public bool IsNotExistsOrRecordEmpty(string file)
{
    if(!File.Exists(file))
    {
        return true;
    }
    using (var sr = new StreamReader(file))
    using (var reader = new CsvReader(sr))
    {
        reader.Read();
        return reader.IsRecordEmpty();
    }    
}
 
public class Foobar
{
    public string ID { get; set; }
    
    public string FirstName { get; set; }
    
    public string LastName { get; set; }
    
    public string Title { get; set; }
}

 

以上

沒有留言:

張貼留言

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。