CSV 文件的读写
Demo
var originFile = @"D:\Demo.csv";
var list = CsvHelper.Read<DemoCsvEntity>(originFile);
var filePath = @"D:\Rslt.csv";
CsvHelper.Write(list, filePath, true);
其中,DemoCsvEntity的属性的顺序是固定的,与csv文件内的表头内容保持一致。
using Microsoft.VisualBasic.FileIO;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
public class CsvHelper
{
/// <summary>
/// 读CSV文件
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
/// <param name="path">文件路径</param>
/// <param name="func">数值转换方法</param>
/// <param name="encoding">编码格式</param>
/// <returns></returns>
public static List<T> Read<T>(string path, Func<string[], T> func = null, Encoding encoding = null) where T : class
{
if (encoding == null)
{
encoding = Encoding.UTF8;
}
if (func == null)
{
func = SetObjValues<T>;
}
var rslt = new List<T>();
using (var parser = new TextFieldParser(path, encoding))
{
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
parser.TrimWhiteSpace = false; // 不忽略字段前后的空格
bool isLine = false;
while (!parser.EndOfData)
{
string[] fields = parser.ReadFields();
if (isLine)
{
var obj = func(fields);
if (obj != null)
{
rslt.Add(obj);
}
}
else
{
// 忽略标题行
isLine = true;
}
}
}
return rslt;
}
/// <summary>
/// 写CSV文件
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
/// <param name="data">数据集合</param>
/// <param name="path">文件路径</param>
/// <param name="append">true追加,false不追加新建</param>
/// <param name="func">字段转换方法</param>
/// <param name="encoding">编码格式</param>
public static void Write<T>(IList<T> data, string path, bool append = false, Func<T, bool, IEnumerable<string>> func = null, Encoding encoding = null) where T : class
{
if (data == null || data.Count == 0)
{
return;
}
if (encoding == null)
{
encoding = Encoding.UTF8;
}
if (func == null)
{
func = GetObjValues;
}
try
{
if (!File.Exists(path) || !append)
{
var fields = func(data[0], true);
string title = FieldsToLine(fields);
File.WriteAllText(path, title, encoding);
}
using (var sw = new StreamWriter(path, true, encoding))
{
foreach (var item in data)
{
var fields = func(item, false);
string line = FieldsToLine(fields);
sw.Write(line);
}
}
}
catch (Exception ex)
{
throw new InvalidOperationException("写入失败!" + ex.Message);
}
}
/// <summary>
/// 字段拼接一行
/// </summary>
/// <param name="fields"></param>
/// <returns></returns>
private static string FieldsToLine(IEnumerable<string> fields)
{
if (fields == null)
{
return string.Empty;
}
var rslt = fields.Select(x =>
{
if (string.IsNullOrWhiteSpace(x))
{
return string.Empty;
}
// 所有字段都加双引号,按需使用
//x = string.Format("\"{0}\"", x.Replace("\"", "\"\""));
return x;
});
return string.Format("{0}{1}", string.Join(",", rslt), Environment.NewLine);
}
/// <summary>
/// 设置对象值
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
/// <param name="data">值集合</param>
/// <returns></returns>
private static T SetObjValues<T>(string[] data) where T : class
{
T rslt = Activator.CreateInstance<T>();
var type = typeof(T);
try
{
var properties = type.GetProperties();
// 确保值的顺序与属性顺序一致,且值类型也一致
for (int i = 0; i < data.Length; i++)
{
var pi = properties[i];
var typeConverter = TypeDescriptor.GetConverter(pi.PropertyType);
var value = typeConverter.ConvertFromString(data[i]);
type.InvokeMember(pi.Name, System.Reflection.BindingFlags.SetProperty, Type.DefaultBinder, rslt, new object[] { value });
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return rslt;
}
/// <summary>
/// 获取对象形式值
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
/// <param name="obj">实体对象</param>
/// <param name="isTitle">true,行首标题;false,每行值</param>
/// <returns></returns>
private static IEnumerable<string> GetObjValues<T>(T obj, bool isTitle) where T : class
{
IEnumerable<string> rslt = null;
if (isTitle)
{
rslt = obj.GetType().GetProperties().Select(x => x.Name);
}
else
{
rslt = obj.GetType().GetProperties().Select(x =>
{
if (x.GetValue(obj) == null)
{
return string.Empty;
}
return x.GetValue(obj).ToString();
});
}
return rslt;
}
}
自定义
CsvHelper 的读写方法中提供默认的转换逻辑,如果想兼容复杂情形,可以自定义转换。
SetObjValues
Read 方法中,SetObjVlues 根据值的字符串集合,设置对象的不同属性值。为保证正确转换,需要确保集合中值的属性与对象的属性顺序是一致的,避免出现转换异常的情况。
如果需要根据文本值,特别设置对应属性的值,可以在 SetObjVlues 的基础上进行扩展。
private T SetObjValues<T>(string[] data) where T: class
{
T rslt = Activator.CreateInstance<T>();
var type = typeof(T);
try
{
var properties = type.GetProperties();
for (int i = 0; i < data.Length; i++)
{
var pi = properties[i];
if (pi.Name == "bPropertName" || pi.Name == "bPropertName2" || pi.Name == "bPropertName3" )
{
if (data[i] == "1") // 整数转换为bool
{
pi.SetValue(rslt, true);
}
else
{
pi.SetValue(rslt, false);
}
}
else if (pi.Name == "PropertyName3") // 指定属性的值
{
if (data[i] == "0")
{
pi.SetValue(rslt, "OK");
}
else
{
pi.SetValue(rslt, "ERROR");
}
}
else // Default
{
var typeConverter = TypeDescriptor.GetConverter(pi.PropertyType);
var value = typeConverter.ConvertFromString(data[i]);
type.InvokeMember(pi.Name, System.Reflection.BindingFlags.SetProperty, Type.DefaultBinder, rslt, new object[] { value });
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return rslt;
}
GetObjValues
如果需要根据属性值,特别显示对应的文本,可以在 GetObjValues 的基础上进行扩展。
private static IEnumerable<string> GetObjValues<T>(T obj, bool isTitle) where T : class
{
IEnumerable<string> rslt = null;
if (isTitle)
{
rslt = obj.GetType().GetProperties().Select(x => x.Name);
}
else
{
rslt = obj.GetType().GetProperties().Select(x =>
{
// bool值用整数显示
if (x.PropertyType == typeof(bool))
{
return (bool)x.GetValue(obj) == true ? "1" : "0";
}
// 指定属性的值用整数显示
else if (x.Name == "PropertyName3")
{
return (string)x.GetValue(obj) == "OK" ? "0" : "1";
}
// default
return x.GetValue(obj) == null ? string.Empty : x.GetValue(obj).ToString();
});
}
return rslt;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2020-04-27 WMI-本地计算机信息