c#简单实现生成csv文件
最近项目中用到Sql Server的DtS数据导入功能。其中dtsx模板的制作和csv的生成是重中之中。在这方面,自己完全是个菜鸟,尤其是dtsx,那玩意让我栽了很多次,幸亏在同事的热心帮助下最终让我得偿所愿,哈哈,真不容易。好了,闲言少叙,下面就记录下自己实现的一个简单的生成csv文件的方式。代码如下:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;
namespace DotNet.Common.Util
{
public static class CsvHelper
{
/// <summary>
/// 保存csv文件
/// </summary>
/// <param name="fileName"></param>
/// <param name="content"></param>
public static bool SaveAsCSV<T>(string fileName, IList<T> listModel) where T : class, new()
{
bool flag = false;
try
{
StringBuilder sb = new StringBuilder();
//通过反射 显示要显示的列
BindingFlags bf = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static;//反射标识
Type objType = typeof(T);
PropertyInfo[] propInfoArr = objType.GetProperties(bf);
string header = string.Empty;
List<string> listPropertys = new List<string>();
foreach (PropertyInfo info in propInfoArr)
{
if (string.Compare(info.Name.ToUpper(), "ID") != 0) //不考虑自增长的id或者自动生成的guid等
{
if (!listPropertys.Contains(info.Name))
{
listPropertys.Add(info.Name);
}
header += info.Name + ",";
}
}
sb.AppendLine(header.Trim(',')); //csv头
foreach (T model in listModel)
{
string strModel = string.Empty;
foreach (string strProp in listPropertys)
{
foreach (PropertyInfo propInfo in propInfoArr)
{
if (string.Compare(propInfo.Name.ToUpper(), strProp.ToUpper()) == 0)
{
PropertyInfo modelProperty = model.GetType().GetProperty(propInfo.Name);
if (modelProperty != null)
{
object objResult = modelProperty.GetValue(model, null);
string result = ((objResult == null) ? string.Empty : objResult).ToString().Trim();
if (result.IndexOf(',') != -1)
{
result = "\"" + result.Replace("\"", "\"\"") + "\""; //特殊字符处理 ?
//result = result.Replace("\"", "“").Replace(',', ',') + "\"";
}
if (!string.IsNullOrEmpty(result))
{
Type valueType = modelProperty.PropertyType;
if (valueType.Equals(typeof(Nullable<decimal>)))
{
result = decimal.Parse(result).ToString("#.#");
}
else if (valueType.Equals(typeof(decimal)))
{
result = decimal.Parse(result).ToString("#.#");
}
else if (valueType.Equals(typeof(Nullable<double>)))
{
result = double.Parse(result).ToString("#.#");
}
else if (valueType.Equals(typeof(double)))
{
result = double.Parse(result).ToString("#.#");
}
else if (valueType.Equals(typeof(Nullable<float>)))
{
result = float.Parse(result).ToString("#.#");
}
else if (valueType.Equals(typeof(float)))
{
result = float.Parse(result).ToString("#.#");
}
}
strModel += result + ",";
}
else
{
strModel += ",";
}
break;
}
}
}
strModel = strModel.Substring(0, strModel.Length - 1);
sb.AppendLine(strModel);
}
string content = sb.ToString();
string dir = Directory.GetCurrentDirectory();
string fullName = Path.Combine(dir, fileName);
if (File.Exists(fullName)) File.Delete(fullName);
using (FileStream fs = new FileStream(fullName, FileMode.CreateNew, FileAccess.Write))
{
StreamWriter sw = new StreamWriter(fs, Encoding.Default);
sw.Flush();
sw.Write(content);
sw.Flush();
sw.Close();
}
flag = true;
}
catch
{
flag = false;
}
return flag;
}
}
}
需要说明的是:
1、生成csv的时候,我们没有考虑实体类和数据库字段的顺序,只是通过反射遍历属性而已。如果要更加直观地看到dtsx模板导出列和csv导入列之间的关系,建议实体类和数据库的字段顺序一致。
2、对于海量数据,这个方法的StringBuilder在保存字符串的时候会有明显的性能问题。这个地方还可以改进,改进的方法请关注老赵的这一篇和即将出现的下一篇。
3、这个生成csv文件的方式不是很灵活,您可以改进成自己需要的方式,比如列名,写入列顺序等自己来配置。
ps:有小数点的数值型保留几位小数看实际项目需要,本文统一保存为1位小数(ToString("#.#")的形式)。
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;
namespace DotNet.Common.Util
{
public static class CsvHelper
{
/// <summary>
/// 保存csv文件
/// </summary>
/// <param name="fileName"></param>
/// <param name="content"></param>
public static bool SaveAsCSV<T>(string fileName, IList<T> listModel) where T : class, new()
{
bool flag = false;
try
{
StringBuilder sb = new StringBuilder();
//通过反射 显示要显示的列
BindingFlags bf = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static;//反射标识
Type objType = typeof(T);
PropertyInfo[] propInfoArr = objType.GetProperties(bf);
string header = string.Empty;
List<string> listPropertys = new List<string>();
foreach (PropertyInfo info in propInfoArr)
{
if (string.Compare(info.Name.ToUpper(), "ID") != 0) //不考虑自增长的id或者自动生成的guid等
{
if (!listPropertys.Contains(info.Name))
{
listPropertys.Add(info.Name);
}
header += info.Name + ",";
}
}
sb.AppendLine(header.Trim(',')); //csv头
foreach (T model in listModel)
{
string strModel = string.Empty;
foreach (string strProp in listPropertys)
{
foreach (PropertyInfo propInfo in propInfoArr)
{
if (string.Compare(propInfo.Name.ToUpper(), strProp.ToUpper()) == 0)
{
PropertyInfo modelProperty = model.GetType().GetProperty(propInfo.Name);
if (modelProperty != null)
{
object objResult = modelProperty.GetValue(model, null);
string result = ((objResult == null) ? string.Empty : objResult).ToString().Trim();
if (result.IndexOf(',') != -1)
{
result = "\"" + result.Replace("\"", "\"\"") + "\""; //特殊字符处理 ?
//result = result.Replace("\"", "“").Replace(',', ',') + "\"";
}
if (!string.IsNullOrEmpty(result))
{
Type valueType = modelProperty.PropertyType;
if (valueType.Equals(typeof(Nullable<decimal>)))
{
result = decimal.Parse(result).ToString("#.#");
}
else if (valueType.Equals(typeof(decimal)))
{
result = decimal.Parse(result).ToString("#.#");
}
else if (valueType.Equals(typeof(Nullable<double>)))
{
result = double.Parse(result).ToString("#.#");
}
else if (valueType.Equals(typeof(double)))
{
result = double.Parse(result).ToString("#.#");
}
else if (valueType.Equals(typeof(Nullable<float>)))
{
result = float.Parse(result).ToString("#.#");
}
else if (valueType.Equals(typeof(float)))
{
result = float.Parse(result).ToString("#.#");
}
}
strModel += result + ",";
}
else
{
strModel += ",";
}
break;
}
}
}
strModel = strModel.Substring(0, strModel.Length - 1);
sb.AppendLine(strModel);
}
string content = sb.ToString();
string dir = Directory.GetCurrentDirectory();
string fullName = Path.Combine(dir, fileName);
if (File.Exists(fullName)) File.Delete(fullName);
using (FileStream fs = new FileStream(fullName, FileMode.CreateNew, FileAccess.Write))
{
StreamWriter sw = new StreamWriter(fs, Encoding.Default);
sw.Flush();
sw.Write(content);
sw.Flush();
sw.Close();
}
flag = true;
}
catch
{
flag = false;
}
return flag;
}
}
}
1、生成csv的时候,我们没有考虑实体类和数据库字段的顺序,只是通过反射遍历属性而已。如果要更加直观地看到dtsx模板导出列和csv导入列之间的关系,建议实体类和数据库的字段顺序一致。
2、对于海量数据,这个方法的StringBuilder在保存字符串的时候会有明显的性能问题。这个地方还可以改进,改进的方法请关注老赵的这一篇和即将出现的下一篇。
3、这个生成csv文件的方式不是很灵活,您可以改进成自己需要的方式,比如列名,写入列顺序等自己来配置。
ps:有小数点的数值型保留几位小数看实际项目需要,本文统一保存为1位小数(ToString("#.#")的形式)。
作者:Jeff Wong
出处:http://jeffwongishandsome.cnblogs.com/
本文版权归作者和博客园共有,欢迎围观转载。转载时请您务必在文章明显位置给出原文链接,谢谢您的合作。