C# 自定義標準 讀寫CSV文件

CSV文件格式標準:

  1. 編碼方式:UTF-8
  2. 行分割符爲換行符(\r\n); 列分割符爲英文逗號(,);
  3. 內容行 第一行爲標題行(即列名);
  4. 約定特殊字符處理標準:

數據源文本

目標文本

英文逗號(,)

英文逗號(,)

出現左側一種或多中情況時,在文本兩側加上英文冒號(“ )

英文冒號(“ )

替換成兩個英文冒號(“”)

換行符(\n)

換行符(\n)

回車符(\r)

回車符(\r)

回車換行符(\r\n)

替換成(\r/\n)

操作示例:

  private DataTable GetData()
        {
            DataTable dta = new DataTable();
            dta.Columns.Add("Code");
            dta.Columns.Add("Name");
            dta.Columns.Add("Address");
            dta.Rows.Add("1", "正常", "中國北京");
            dta.Rows.Add("1", "逗號", "中國,北京");
            dta.Rows.Add("1", "換行", "中國\n北京");
            dta.Rows.Add("1", "回車換行", "中國\r\n北京");
            dta.Rows.Add("1", "逗號換行", "中,國北\n京");
            dta.Rows.Add("1", "1個單引號", "中國'北京");
            dta.Rows.Add("1", "2個單引號", "中國'北'京");
            dta.Rows.Add("1", "1個雙引號", "中國\"北京");
            dta.Rows.Add("1", "2個雙引號", "中國\"北\"京");
            dta.Rows.Add("1", "1個單雙引號", "中國'北\"京");
            return dta;
        }

        private void WCsv_Loaded(object sender, RoutedEventArgs e)
        {
            string path = $@"C:\Users\Administrator\Desktop\ABC.csv";
            string path2 = $@"C:\Users\Administrator\Desktop\ABC2.csv";
            DataTable dta = GetData();
            string errInfo;
            //把數據集寫到文件1
            bool isOk =FuncCsv. CsvWrite(dta, path, out errInfo);
            //讀取文件1
            DataTable dt2 = FuncCsv.CsvRead(path, out errInfo);
            //把文件1的數據寫到文件2,比較文件是否一致
            bool isOk2= FuncCsv.CsvWrite(dt2, path2, out errInfo);
        }

自定義類:

using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;

namespace Wpfjsj
{
    /// <summary>
    /// CSV自定義類
    /// </summary>
   public static class FuncCsv
    {
        private static readonly object Obj = new object();
        /// <summary>
        /// 把數據集寫到CSV文件
        /// </summary>
        /// <param name="dt">數據集</param>
        /// <param name="path">文件路徑</param>
        /// <param name="errInfo">異常信息</param>
        /// <param name="en">編碼方式 默認爲空(UFT-8)</param>
        /// <param name="isConHeader">是否包含標題行(列名) 默認包含</param>
        /// <returns>返回值 寫入是否成功</returns>
        public static bool CsvWrite(DataTable dt, string path, out string errInfo, Encoding en = null, bool isConHeader = true)
        {
            lock (Obj)
            {
                try
                {
                    errInfo = "";
                    //以半角逗號(即,)作分隔符,列爲空也要表達其存在。  
                    //列內容如存在半角逗號(即,)則用半角引號(即"")將該字段值包含起來。  
                    //列內容如存在半角引號(即")則應替換成半角雙引號("")轉義,並用半角引號(即"")將該字段值包含起來。  
                    StringBuilder sb = new StringBuilder();
                    if (isConHeader)
                    {
                        for (int m = 0; m < dt.Columns.Count; m++)
                        {
                            sb.Append(dt.Columns[m].ColumnName);
                            if (m != dt.Columns.Count - 1)
                                sb.Append(",");
                        }
                        sb.Append("\r\n");
                    }
                    foreach (DataRow row in dt.Rows)
                    {
                        for (int i = 0; i < dt.Columns.Count; i++)
                        {
                            var colum = dt.Columns[i];
                            if (i != 0) sb.Append(",");
                            string str = row[colum].ToString();
                            sb.Append(colum.DataType == typeof(string) ? ConvStr_CsvWrite(str) : str);
                        }
                        sb.Append("\r\n");
                    }

                    StreamWriter sw = new StreamWriter(path, false, en ?? Encoding.UTF8);
                    sw.Write(sb);
                    sw.Flush();
                    sw.Close();
                    return true;
                }
                catch (Exception ex)
                {
                    errInfo = ex.Message;
                    return false;
                }
            }
        }

        private static readonly object Obj1 = new object();
        /// <summary>
        /// 讀取CSV文件內容到數據集
        /// </summary>
        /// <param name="path">文件路徑</param>
        /// <param name="errInfo">異常信息</param>
        /// <param name="en">編碼方式 默認爲空(UFT-8)</param>
        /// <param name="isConHeader">文件內容是否包含標題行(列名),默認包含</param>
        /// <returns>返回的數據集</returns>
        public static DataTable CsvRead(string path, out string errInfo, Encoding en = null, bool isConHeader = true)
        {
            lock (Obj1)
            {
                errInfo = "";
                DataTable dt = new DataTable();
                try
                {
                    //讀取文件
                    StreamReader sr = new StreamReader(path, en ?? Encoding.UTF8);
                    string result = sr.ReadToEnd();
                    sr.Close();
                    //解析文件
                    int index = 0;
                    foreach (string content in result.Split(new[] {"\r\n"}, StringSplitOptions.None))
                    {
                        if (string.IsNullOrWhiteSpace(content)) continue;
                        string[] strCols = StrToStrArray(content);
                        if (index == 0)
                        {
                            if (isConHeader)
                            {
                                foreach (string str in strCols)
                                    dt.Columns.Add(str);
                                index++;
                                continue;
                            }
                            //自定義標題
                            for (int m = 1; m <= strCols.Length; m++)
                                dt.Columns.Add($"Col{m}");
                            index = 1;
                        }
                        dt.Rows.Add(strCols);
                    }
                }
                catch (Exception ex)
                {
                    errInfo = ex.Message;
                }
                return dt;
            }
        }

        private static string[] StrToStrArray(string strLine)
        {
            string[] strFirsts = strLine.Split(',');
            List<string> list = new List<string>();
            StringBuilder sbCombie = new StringBuilder();
            foreach (string str in strFirsts)
            {
                int indexOneFirst = str.IndexOf('\"');
                //常規字符串
                if (sbCombie.Length == 0 && indexOneFirst < 0)
                {
                    list.Add(str);
                    continue;
                }

                //字符串末尾 冒號連續出現的次數爲奇數 則字符串結束
                int count = 0;
                for (int n = str.Length - 1; n >= 0; n--)
                {
                    if (str[n] == '\"')
                        count++;
                    else
                        break;
                }

                //源字符串帶冒號 不帶逗號
                if (sbCombie.Length == 0 && indexOneFirst == 0 && count % 2 == 1)
                {
                    list.Add(ConvStr_CsvRead(str));
                    continue;
                }

                if (count % 2 == 0)
                {
                    sbCombie.Append($"{str},");
                }
                else
                {
                    sbCombie.Append(str);
                    list.Add(ConvStr_CsvRead(sbCombie.ToString()));
                    sbCombie.Clear();
                }
            }
            return list.ToArray();
        }

        private static string ConvStr_CsvRead(string str)
        {
            if (str.Contains('\"'))
            {
                str = str.Replace("\r/\n", "\r\n").Replace("\"\"", "\"");
                return str.Substring(1, str.Length - 2);
            }
            return str;
        }

        private static string ConvStr_CsvWrite(string str)
        {
            if (str.Contains(',') || str.Contains('\n') || str.Contains('\r') || str.Contains('"'))
                return $"\"{str.Replace("\r\n", "\r/\n").Replace("\"", "\"\"")}\"";
            return str;
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章