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

/// <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"]));
}

Comments

# by kennyshu

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

# by Jeffrey

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

# by 路過的貓

用OLEDB的方式去開EXCEL會比較快嗎? 也可以處理雙引號問題

# by Jeffrey

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

# by 路過的貓

欄位格式的問題,我個人解法是第一行資料都用中文字(欄位名稱) 莫名多出欄位,如果原始檔案(CSV)就有多出多餘的逗點的話會這樣,尤其如果用EXCEL開起來看又看不出所以然 文字被當數字,我是用 1.Extended Properties=Text; 2.搭配設定檔Schema.ini Schema.ini 內容,要跟 CSV 放在同個資料夾 [檔名.csv] Format = CSVDelimited ColNameHeader = False MaxScanRows = 1 (這代表掃描內容時,只採第一行做為欄位格式的判斷) 因為當初找轉檔解決辦法找得一個頭兩個大....... 都沒有一個完美的解法(有些是遇到雙引號內包逗點、雙引號、換行符號時會失常) 有些是文字數字會格式亂跳 最後配出這個折衷方案,請參考....

# by Jeffrey

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

Post a comment