最近忙的一个项目中有对csv数据的操作,主要是读的问题,以为很简单,不就是数据按行读取后,用逗号来分隔吗!
刚开始确实也是这么做的,直到遇到了单元格中含有逗号的情况,就懵逼了。
举个栗子:
有这么一个csv文件,通过用txt方式打开后
正确的结果应该是按照每列的数据读取,也就是
column1: "1,3,44,55"
column2:2
column3:"""231"",""232"""
column4:"3,4,5"
关于每列数据是怎么处理逗号和分号的情况,还是请度娘帮忙吧,我的理解是单元格中如果有逗号的情况,在转换为txt的时候会用双引号来表示该单元格,如:column1;如果有分号的情况,在用txt打开的时候分号会变为两个,如果该单元格还有逗号的情况,还会有两个分号表示该单元格,如:column3.
要怎样把这行数据正确的读取出来呢?达到我要的效果呢,就会涉及到对逗号和双引号的处理了,先看处理结果:
每个数据对应着每个单元格的内容,至于怎么处理就和具体业务有关系了。
上代码:
循环读取csv每行内容:
/// <summary>
/// 读取csv指定列类容
/// </summary>
/// <param name="fs"></param>
/// <returns></returns>
public static List<CSVData> GetCSVValue(FileStream fs)
{
List<CSVData> results = new List<CSVData>();
StreamReader reader = new StreamReader(fs, System.Text.Encoding.UTF8);
int m = 0;
string strLine = "";
try
{
while ((strLine = reader.ReadLine()) != null)
{
if (m == 0)
{
// 第一行表头不读取
m = m + 1;
continue;
}
CSVData csvData = new CSVData();
// 将csv转换为string 数组
string[] split = Utils.GetCSVValue(strLine).ToArray();
// csvData 根据自身业务需要,抽取csv的那些列
results.Add(csvData);
}
reader.Close();
fs.Close();
}
catch (Exception ex)
{
log.Error(string.Format(ex.Message));
}
return results;
}
Utils.GetCSVValue函数实现
/// <summary>
/// 处理双引号
/// </summary>
/// <param name="line"></param>
/// <returns></returns>
public static string HandleQuote(string line)
{
if (line.IsEmpty() || line.Length == 0)
{
return "";
}
else
{
string value = "";
int chIndex = 0;
// 双引号
if (line[0] == '\"')
{
chIndex = line.IndexOf('\"', 1);
if (chIndex == -1)
{
value = line;
}
else
{
value = line.Substring(0, chIndex + 1);
// 判断下一个字符是否是,注意越界
if (chIndex + 1 < line.Length)
{
char c = line[chIndex + 1];
if (c != ',')
{
line = line.Substring(chIndex + 1);
value += HandleQuote(line);
}
}
}
}
return value;
}
}
/// <summary>
/// 递归取值
/// </summary>
/// <param name="line"></param>
/// <param name="spilts"></param>
public static List<string> GetCSVValue(string line)
{
List<string> spilts = new List<string>();
if (line.IsEmpty() || line.Length == 0)
{
return spilts;
}
else
{
string value = "";
int chIndex = 0;
// 双引号
if (line[0] == '\"')
{
value = HandleQuote(line);
spilts.Add(value);
// 判断是否是最后一个
if (value.Length + 1 < line.Length)
{
line = line.Substring(value.Length + 1);
spilts.AddRange(GetCSVValue(line));
}
}
else
{
chIndex = line.IndexOf(',');
if (chIndex == -1)
{
spilts.Add(line);
}
else
{
value = line.Substring(0, chIndex);
spilts.Add(value);
// 判断是否是最后一个
if (value.Length + 1 < line.Length)
{
line = line.Substring(value.Length + 1);
spilts.AddRange(GetCSVValue(line));
}
}
}
}
return spilts;
}
可能会用到的引用:
using System.Data;
using System.IO;
using System;
using System.Text;
using System.Collections.Generic;
using System.Text.RegularExpressions;
大致记录完成,方便以后自己查阅,也为有需要的童鞋,提供帮助,如果有兴趣就仔细研究递归部分代码,如有问题,还请指正,也希望还有更优化的方案。