CSV文件帮助类

操作 CSV 文件帮助类

简介

工作中用户提供 CSV 文件作为参考数据使用,需要读取到系统中进行相关计算
CSV(逗号分隔值文件格式)其文件以纯文本形式存储表格数据,分隔字符也可以不是逗号,可用Excel编辑的表格文件。
CSVHelper 帮助类主要提供内存表格DataTable互相转换,以正则表达式与截取拼接。

CSV文件操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/// <summary>
/// DataTable转换为CSV
/// </summary>
/// <param name="strSource">CSV文件路径</param>
/// <param name="dtSourceData">DataTable数据</param>
/// <returns>成功返回true,失败返回false</returns>
public static bool DataTableConversionCSV(string strSource, DataTable dtSourceData)
{
try
{
if (string.IsNullOrEmpty(strSource) || dtSourceData.Rows.Count < 1)
{
return false;
}
FileStream fileStream = new FileStream(Path.ChangeExtension(strSource, "csv"), FileMode.Create);
StreamWriter streamWriter = new StreamWriter(fileStream);
//记录当前读取到的一行数据
string strRowOfData = string.Empty;
//循环保存列名
for (int iColumnsName = 0; iColumnsName < dtSourceData.Columns.Count; iColumnsName++)
{
strRowOfData += string.Format("{0}{1}{0}", "\"", dtSourceData.Columns[iColumnsName].ColumnName.ToString());
if (iColumnsName < dtSourceData.Columns.Count - 1)
{
strRowOfData += ",";
}
}
streamWriter.WriteLine(strRowOfData);
//循环保存数据
for (int iRow = 0; iRow < dtSourceData.Rows.Count; iRow++)
{
strRowOfData = string.Empty;
for (int iColumns = 0; iColumns < dtSourceData.Columns.Count; iColumns++)
{
strRowOfData += string.Format("{0}{1}{0}", "\"", dtSourceData.Rows[iRow][iColumns].ToString());
if (iColumns < dtSourceData.Columns.Count - 1)
{
strRowOfData += ",";
}
}
streamWriter.WriteLine(strRowOfData);
}
streamWriter.Close();
fileStream.Close();
return true;
}
catch (Exception ex)
{
TXTHelper.Logs(ex.ToString());
return false;
}
}

/// <summary>
/// CSV转换为DataTable(默认 UTF8 编码)
/// </summary>
/// <param name="strSource">CSV文件路径</param>
/// <returns>成功返回CSV的DataTable,失败返回NULL</returns>
public static DataTable CSVConversionDataTable(string strSource)
{
try
{
if (string.IsNullOrEmpty(strSource) || !File.Exists(strSource))
{
return null;
}
DataTable dtTargetData = new DataTable();
//初始化 System.IO.FileStream 类的新实例
FileStream fileStreamOpen = new FileStream(strSource, FileMode.Open, FileAccess.Read);
//从当前流中读取一行字符并将数据作为字符串返回
StreamReader streamReader = new StreamReader(fileStreamOpen, Encoding.UTF8);
//记录当前读取到的一行数据
string strRowOfData;
//记录当前是否为标题行
bool boolIsFirst = true;
//循环获得CSV文件数据
while ((strRowOfData = streamReader.ReadLine()) != null)
{
//从当前 System.String 对象中移除所有前导和尾随空白字符
strRowOfData.Trim();
//替换两遍连续两个 ,, 为 ,"",(希望数据里不存在两个逗号相连的情况)
strRowOfData = strRowOfData.Replace(",,", ",\"\",");
strRowOfData = strRowOfData.Replace(",,", ",\"\",");
//如果截取第一个字符是 ',' 则在最前面加双引号
if (strRowOfData.Substring(0, 1) == ",")
{
strRowOfData = string.Format("\"\"{0}", strRowOfData);
}
//根据CSV规则分割字符串
string strRegexCSV = string.Format("[^\",]+|\"(?:[^\"]|\"\")*\"");
Regex regexCSV = new Regex(strRegexCSV);
MatchCollection matchCollection = regexCSV.Matches(strRowOfData);
//判断是否为标题行
if (boolIsFirst)
{
foreach (Match mColumnValue in matchCollection)
{
dtTargetData.Columns.Add(InterceptionQuotes(mColumnValue.Value));
}
boolIsFirst = false;
}
else
{
DataRow drTargetData = dtTargetData.NewRow();
for (int iColumn = 0; iColumn < dtTargetData.Columns.Count && iColumn < matchCollection.Count; iColumn++)
{
drTargetData[iColumn] = InterceptionQuotes(matchCollection[iColumn].Value);
}
dtTargetData.Rows.Add(drTargetData);
}
}
streamReader.Close();
fileStreamOpen.Close();
return dtTargetData;
}
catch (Exception ex)
{
TXTHelper.Logs(ex.ToString());
return null;
}
}

/// <summary>
/// CSV转换为DataTable
/// </summary>
/// <param name="strSource">CSV文件路径</param>
/// <param name="encoding">The character encoding to use.</param>
/// <returns>成功返回CSV的DataTable,失败返回NULL</returns>
public static DataTable CSVConversionDataTable(string strSource, Encoding encoding)
{
try
{
if (string.IsNullOrEmpty(strSource) || !File.Exists(strSource))
{
return null;
}
DataTable dtTargetData = new DataTable();
//初始化 System.IO.FileStream 类的新实例
FileStream fileStreamOpen = new FileStream(strSource, FileMode.Open, FileAccess.Read);
//从当前流中读取一行字符并将数据作为字符串返回
StreamReader streamReader = new StreamReader(fileStreamOpen, encoding);
//记录当前读取到的一行数据
string strRowOfData;
//记录当前是否为标题行
bool boolIsFirst = true;
//循环获得CSV文件数据
while ((strRowOfData = streamReader.ReadLine()) != null)
{
//从当前 System.String 对象中移除所有前导和尾随空白字符
strRowOfData.Trim();
//替换两遍连续两个 ,, 为 ,"",(希望数据里不存在两个逗号相连的情况)
strRowOfData = strRowOfData.Replace(",,", ",\"\",");
strRowOfData = strRowOfData.Replace(",,", ",\"\",");
//如果截取第一个字符是 ',' 则在最前面加双引号
if (strRowOfData.Substring(0, 1) == ",")
{
strRowOfData = string.Format("\"\"{0}", strRowOfData);
}
//根据CSV规则分割字符串
string strRegexCSV = string.Format("[^\",]+|\"(?:[^\"]|\"\")*\"");
Regex regexCSV = new Regex(strRegexCSV);
MatchCollection matchCollection = regexCSV.Matches(strRowOfData);
//判断是否为标题行
if (boolIsFirst)
{
foreach (Match mColumnValue in matchCollection)
{
dtTargetData.Columns.Add(InterceptionQuotes(mColumnValue.Value));
}
boolIsFirst = false;
}
else
{
DataRow drTargetData = dtTargetData.NewRow();
for (int iColumn = 0; iColumn < dtTargetData.Columns.Count && iColumn < matchCollection.Count; iColumn++)
{
drTargetData[iColumn] = InterceptionQuotes(matchCollection[iColumn].Value);
}
dtTargetData.Rows.Add(drTargetData);
}
}
streamReader.Close();
fileStreamOpen.Close();
return dtTargetData;
}
catch (Exception ex)
{
TXTHelper.Logs(ex.ToString());
return null;
}
}

/// <summary>
/// 截取字符串前后双引号
/// </summary>
/// <param name="strSource">源字符串</param>
/// <returns>截取后字符串</returns>
private static string InterceptionQuotes(string strSource)
{
try
{
if (strSource[0] == '\"' && strSource[strSource.Length - 1] == '\"')
{
return strSource.Substring(1, strSource.Length - 2);
}
else
{
return strSource;
}
}
catch (Exception ex)
{
TXTHelper.Logs(ex.ToString());
return string.Empty;
}
}