網頁

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; }
}

 

以上

沒有留言:

張貼留言