CODE-將CSV檔案內容轉換成ADO.NET DataTable物件

寫給同事用的工具函數,隨手貼文分享:

/// <summary>
/// 將CSV內容字串轉成DataTable(全部欄位都視為string,有需要請自行轉換), 不支援""包夾格式
/// </summary>
/// <param name="csvContent">整個CSV的內容</param>
/// <param name="firstRowAsHeader">第一列是否為欄位名稱,若無則以C1, C2自動命名</param>
/// <returns></returns>
public static DataTable ConvertCSVtoDataTable(string csvContent, 
    bool firstRowAsHeader)
{
    DataTable t = new DataTable();
    using (StringReader sr = new StringReader(csvContent))
    {
        string line = null;
        bool colCreated = false;
        while ((line = sr.ReadLine()) != null)
        {
            string[] p = line.Split(',');
            if (!colCreated)
            {
                int idx = 1;
                foreach (string s in p)
                {
                    try
                    {
                        t.Columns.Add(
                            //第一欄是否有欄位名稱? 無則用C1, C2自動編號
                            firstRowAsHeader ? s : "C" + idx.ToString(),
                            typeof(string)
                            );
                    }
                    catch (Exception e1)
                    {
                        throw new ApplicationException(
                            "新增欄位失敗! 欄位名稱=" + s + "\n" + e1.ToString());
                    }
                    idx++;
                }
                colCreated = true;
                //首欄若為欄名,則不當資料處理
                if (firstRowAsHeader) continue;
            }
            try
            {
                t.Rows.Add(p);
            }
            catch (Exception e2)
            {
                throw new ApplicationException("資料匯入失敗!\n資料=" + line + 
                    "\n錯誤訊息:" + e2.ToString());
            }
        }
    }
    return t;
}
 
private static void test()
{
    string csv = "ID,Name,Score\n1,Jeffrey,200\n2,Darkthread,999";
    //Or you can read data from file
    //string csv = System.IO.File.ReadAllText("B:\\mydata.csv");
    DataTable t = ConvertCSVtoDataTable(csv, true);
    Debug.WriteLine("RowCount=" + t.Rows.Count);
    foreach (DataRow r in t.Rows)
        Debug.WriteLine(string.Format("{0}=>{1}", r["Name"], r["Score"]));
    csv = "1,Jeffrey,200\n2,Darkthread,999";
    t = ConvertCSVtoDataTable(csv, false);
    Debug.WriteLine("RowCount=" + t.Rows.Count);
    foreach (DataRow r in t.Rows)
        Debug.WriteLine(string.Format("{0}=>{1}", r["C2"], r["C3"]));
}
Published 30 October 2009 03:06 PM 由 Jeffrey


意見

# kennyshu said on 30 October, 2009 10:40 AM

很好奇這種簡單的小工具你同事竟然要麻煩黑大寫?

# Jeffrey said on 31 October, 2009 11:01 AM

to kennyshu, 部門裡卧虎藏龍,擅長於其他領域的高手卻未必是.NET專家(但開始逐步轉向.NET是趨勢),我寫五分鐘的Code,可以省卻COBOL前輩(純舉例)盲目摸索兩天半,怎麼算都是宗划算的買賣。(我一直企望有人這種方式幫助我,所以我有能力就這麼做囉~~)

# 路過的貓 said on 01 November, 2009 11:51 PM

用OLEDB的方式去開EXCEL會比較快嗎?

也可以處理雙引號問題

# Jeffrey said on 02 November, 2009 07:19 AM

to 路過的貓, 不知運氣欠佳還是怎樣,遇過好幾次OLEDB解析錯誤的狀況,莫名多出欄位、文字被當數字去前置零... 等等,後來就不怎麼愛它了。

# 路過的貓 said on 06 November, 2009 02:25 AM

欄位格式的問題,我個人解法是第一行資料都用中文字(欄位名稱)

莫名多出欄位,如果原始檔案(CSV)就有多出多餘的逗點的話會這樣,尤其如果用EXCEL開起來看又看不出所以然

文字被當數字,我是用

1.Extended Properties=Text;

2.搭配設定檔Schema.ini

Schema.ini 內容,要跟 CSV 放在同個資料夾

[檔名.csv]

Format = CSVDelimited

ColNameHeader = False

MaxScanRows = 1  (這代表掃描內容時,只採第一行做為欄位格式的判斷)

因為當初找轉檔解決辦法找得一個頭兩個大.......

都沒有一個完美的解法(有些是遇到雙引號內包逗點、雙引號、換行符號時會失常)

有些是文字數字會格式亂跳

最後配出這個折衷方案,請參考....

# Jeffrey said on 06 November, 2009 03:36 PM

to 路過的貓, 感謝分享,我記下來了(沙沙沙),衝著您的面子,我下次會再給OLEDB一次機會的。

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 

請輸入以上的數字:

搜尋

Go

<October 2009>
SunMonTueWedThuFriSat
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567
 
RSS
【工商服務】
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


BlogLook Score and Rank

Syndication