CSV文件格式標準:
- 編碼方式:UTF-8
- 行分割符爲換行符(\r\n); 列分割符爲英文逗號(,);
- 內容行 第一行爲標題行(即列名);
- 約定特殊字符處理標準:
數據源文本 |
目標文本 |
|
英文逗號(,) |
英文逗號(,) |
出現左側一種或多中情況時,在文本兩側加上英文冒號(“ ) |
英文冒號(“ ) |
替換成兩個英文冒號(“”) |
|
換行符(\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;
}
}
}