zoukankan      html  css  js  c++  java
  • C#使用Linq to csv读取.csv文件数据3_源码改造_支持设置标题行&标题映射&自动打印并忽略错误行数据&定义数据格式

      使用csv文件存储数据比excel更加轻量级,支持的场景更加丰富,可以完全自定义,不受excel约束。  但是对csv文件的解析和读取,网上的资料又不是很多,这里通过拿来linq to csv的源码并在其基础上进行扩展,以支持遇到的一些问题。

      主要扩展的功能点:

        1-支持设置标题行 (源码仅支持设置首行是否为标题行)

        2-支持设置标题跟数据的映射关系 (源码通过下标设置数据关系,这一点如果标题行过多时,数位置是很头疼的,尤其是在多列中再插入一列...而通过标题跟数据映射就很简单了,自动寻找下标)

        2-自动打印错误行数据并忽略错误行数据(这点和源码差不多)

        3-定义数据格式(和源码一致)

      我的前两篇关于csv的帮助文章也可以参考下:

      C#使用Linq to csv读取.csv文件数据

      C#使用Linq to csv读取.csv文件数据2_处理含有非列名数据的方法(说明信息等)

    改造完整代码如下:

      

      1-Csv文件类特性标记:

    /// <summary>
        /// Csv文件类特性标记
        /// </summary>
        [System.AttributeUsage(System.AttributeTargets.Field | System.AttributeTargets.Property, AllowMultiple = false)]
        public class CsvColumnAttribute : System.Attribute
        {
            /// <summary>
            /// 标题
            /// </summary>
            public string Title { get; set; }
            /// <summary>
            /// 字符输出格式(数字和日期类型需要)
            /// </summary>
            public string OutputFormat { get; set; }
    
            public CsvColumnAttribute()
            {
                Title = "";
                OutputFormat = "";
            }
    
            public CsvColumnAttribute(string title, string outputFormat)
            {
                Title = title;
                OutputFormat = outputFormat;
            }
        }
    CsvColumnAttribute

      2-CsvFileDescription:

    public class CsvFileDescription
        {
            public CsvFileDescription() : this(1)
            {
            }
            public CsvFileDescription(int titleRawIndex) : this(',', titleRawIndex, Encoding.UTF8)
            {
            }
            public CsvFileDescription(char separatorChar, int titleRawIndex, Encoding encoding)
            {
                this.SeparatorChar = separatorChar;
                this.TitleRawIndex = titleRawIndex;
                this.Encoding = encoding;
            }
    
            /// <summary>
            /// CSV文件字符编码
            /// </summary>
            public Encoding Encoding { get; set; }
    
            /// <summary>
            /// 分隔符(默认为(,),也可以是其他分隔符如(	))
            /// </summary>
            public char SeparatorChar { get; set; }
            /// <summary>
            /// 标题所在行位置(默认为1,没有标题填0)
            /// </summary>
            public int TitleRawIndex { get; set; }
    
        }
    CsvFileDescription

      3-字段映射类:

    /// <summary>
        /// 字段映射类
        /// </summary>
        public class FieldMapper
        {
            /// <summary>
            /// 属性信息
            /// </summary>
            public PropertyInfo PropertyInfo { get; set; }
            /// <summary>
            /// 标题
            /// </summary>
            public string CSVTitle { get; set; }
            /// <summary>
            /// 标题下标位置
            /// </summary>
            public int CSVTitleIndex { get; set; }
            /// <summary>
            /// 字符输出格式(数字和日期类型需要)
            /// </summary>
            public string OutputFormat { get; set; }
    
            public static List<FieldMapper> GetModelFieldMapper<T>()
            {
                List<FieldMapper> fieldMapperList = new List<FieldMapper>(100);
    
                List<PropertyInfo> tPropertyInfoList = typeof(T).GetProperties().ToList();
                CsvColumnAttribute csvColumnAttribute = null;
                int beginTitleIndex = 1;
                foreach (var tPropertyInfo in tPropertyInfoList)
                {
                    csvColumnAttribute = (CsvColumnAttribute)tPropertyInfo.GetCustomAttribute(typeof(CsvColumnAttribute));
                    if (csvColumnAttribute != null)
                    {
                        fieldMapperList.Add(new FieldMapper
                        {
                            PropertyInfo = tPropertyInfo,
                            CSVTitle = csvColumnAttribute.Title,
                            CSVTitleIndex = beginTitleIndex,
                            OutputFormat = csvColumnAttribute.OutputFormat
                        });
                        beginTitleIndex++;
                    }
                }
                return fieldMapperList;
            }
    
        }
    FieldMapper

      4-CsvHelper帮助类:

    public class CsvHelper
        {
            /// <summary>
            /// 日志
            /// </summary>
            private ILogger _Logger { get; set; }
    
            public CsvHelper(ILogger<CsvHelper> logger)
            {
                this._Logger = logger;
            }
    
            public List<T> Read<T>(string filePath, CsvFileDescription fileDescription) where T : class, new()
            {
                List<T> tList = new List<T>(50 * 10000);
    
                T t = null;
                int currentRawIndex = 1;
    
                if (File.Exists(filePath))
                {
                    using (StreamReader streamReader = new StreamReader(filePath, fileDescription.Encoding))
                    {
                        Dictionary<int, FieldMapper> fieldMapperDic = FieldMapper.GetModelFieldMapper<T>().ToDictionary(m => m.CSVTitleIndex);
                        string rawValue = null;
                        string[] rawValueArray = null;
                        PropertyInfo propertyInfo = null;
                        string propertyValue = null;
                        bool rawReadEnd = false;
    
                        bool isExistSplitChart = false;
                        do
                        {
                            rawValue = streamReader.ReadLine();
    
                            //标题行
                            if (currentRawIndex > fileDescription.TitleRawIndex)
                            {
                                if (!string.IsNullOrEmpty(rawValue))
                                {
                                    //替换字符串含有分隔符为{分隔符},最后再替换回来
                                    if (rawValue.Contains("""))
                                    {
                                        isExistSplitChart = true;
    
                                        int yhBeginIndex = 0;
                                        int yhEndIndex = 0;
                                        string yhText = null;
                                        do
                                        {
                                            yhBeginIndex = StringHelper.GetIndexOfStr(rawValue, """, 1);
                                            yhEndIndex = StringHelper.GetIndexOfStr(rawValue, """, 2);
                                            yhText = rawValue.Substring(yhBeginIndex, (yhEndIndex - yhBeginIndex + 1));
                                            string newYHText = yhText.Replace(""", "").Replace(fileDescription.SeparatorChar.ToString(), "{分隔符}");
                                            rawValue = rawValue.Replace(yhText, newYHText);
                                        } while (rawValue.Contains("""));
                                    }
    
                                    rawValueArray = rawValue.Split(fileDescription.SeparatorChar);
    
                                    t = new T();
                                    bool isExistException = false;
                                    foreach (var fieldMapper in fieldMapperDic)
                                    {
                                        try
                                        {
                                            propertyInfo = fieldMapper.Value.PropertyInfo;
                                            propertyValue = rawValueArray[fieldMapper.Key - 1];
                                            if (!string.IsNullOrEmpty(propertyValue))
                                            {
                                                if (isExistSplitChart && propertyValue.Contains("{分隔符}"))
                                                {
                                                    propertyValue = propertyValue.Replace("{分隔符}", fileDescription.SeparatorChar.ToString());
                                                }
    
                                                TypeHelper.SetPropertyValue(t, propertyInfo.Name, propertyValue);
                                            }
                                        }
                                        catch (Exception e)
                                        {
                                            isExistException = true;
                                            this._Logger.LogWarning(e, $"第{currentRawIndex}行数据{propertyValue}转换属性{propertyInfo.Name}-{propertyInfo.PropertyType.Name}失败!文件路径:{filePath}");
                                            break;
                                        }
                                    }
                                    if (isExistException == false)
                                    {
                                        tList.Add(t);
                                    }
                                }
                                else
                                {
                                    rawReadEnd = true;
                                }
                            }
                            currentRawIndex++;
                        } while (rawReadEnd == false);
                    }
                }
    
    
                return tList;
            }
    
            public void WriteFile<T>(string path, List<T> tList, CsvFileDescription fileDescription) where T : class, new()
            {
                if (!string.IsNullOrEmpty(path))
                {
                    string fileDirectoryPath = null;
                    if (path.Contains("\"))
                    {
                        fileDirectoryPath = path.Substring(0, path.LastIndexOf('\'));
                    }
                    else
                    {
                        fileDirectoryPath = path.Substring(0, path.LastIndexOf('/'));
                    }
                    if (!Directory.Exists(fileDirectoryPath))
                    {
                        Directory.CreateDirectory(fileDirectoryPath);
                    }
    
                    int dataCount = tList.Count;
                    Dictionary<int, FieldMapper> fieldMapperDic = FieldMapper.GetModelFieldMapper<T>().ToDictionary(m => m.CSVTitleIndex);
                    int titleCount = fieldMapperDic.Keys.Max();
                    string[] rawValueArray = new string[titleCount];
                    StringBuilder rawValueBuilder = new StringBuilder();
                    string rawValue = null;
                    T t = null;
                    PropertyInfo propertyInfo = null;
                    int currentRawIndex = 1;
                    int tIndex = 0;
    
                    using (StreamWriter streamWriter = new StreamWriter(path, false, fileDescription.Encoding))
                    {
                        do
                        {
                            try
                            {
                                rawValue = "";
    
    #if DEBUG
                                if (currentRawIndex % 10000 == 0)
                                {
                                    this._Logger.LogInformation($"已写入文件:{path},数据量:{currentRawIndex}");
                                }
    #endif
    
                                if (currentRawIndex >= fileDescription.TitleRawIndex)
                                {
                                    //清空数组数据
                                    for (int i = 0; i < titleCount; i++)
                                    {
                                        rawValueArray[i] = "";
                                    }
    
                                    if (currentRawIndex > fileDescription.TitleRawIndex)
                                    {
                                        t = tList[tIndex];
                                        tIndex++;
                                    }
                                    foreach (var fieldMapperItem in fieldMapperDic)
                                    {
                                        //写入标题行
                                        if (currentRawIndex == fileDescription.TitleRawIndex)
                                        {
                                            rawValueArray[fieldMapperItem.Key - 1] = fieldMapperItem.Value.CSVTitle;
                                        }
                                        //真正的数据从标题行下一行开始写
                                        else
                                        {
                                            propertyInfo = fieldMapperItem.Value.PropertyInfo;
                                            object propertyValue = propertyInfo.GetValue(t);
                                            string formatValue = null;
                                            if (propertyValue != null)
                                            {
                                                if (propertyInfo.PropertyType is IFormattable && !string.IsNullOrEmpty(fieldMapperItem.Value.OutputFormat))
                                                {
                                                    formatValue = ((IFormattable)propertyValue).ToString(fieldMapperItem.Value.OutputFormat, null);
                                                }
                                                else
                                                {
                                                    formatValue = propertyValue.ToString();
                                                }
    
                                                //如果属性值含有分隔符,则使用双引号包裹
                                                if (formatValue.Contains(fileDescription.SeparatorChar.ToString()))
                                                {
                                                    formatValue = $""{formatValue}"";
                                                }
                                                rawValueArray[fieldMapperItem.Key - 1] = formatValue;
                                            }
                                        }
                                    }
                                    rawValue = string.Join(fileDescription.SeparatorChar, rawValueArray);
                                }
                                rawValueBuilder.Append(rawValue + "
    ");
                            }
                            catch (Exception e)
                            {
                                this._Logger.LogWarning(e, $"(异常)Excel第{currentRawIndex}行,数据列表第{tIndex + 1}个数据写入失败!rawValue:{rawValue}");
                                throw;
                            }
    
                            currentRawIndex++;
                        } while (tIndex < dataCount);
                        streamWriter.Write(rawValueBuilder.ToString());
    
                        streamWriter.Close();
                        streamWriter.Dispose();
                    }
                }
            }
    
        }
    CsvHelper

      示例:

      使用类:

    /// <summary>
    /// CSV文件数据
    /// </summary>
    public class CSVModel
    {
        /// <summary>
        /// 公司账号
        /// </summary>
        [CsvColumn(Title = "Company Account")]
        public string CompanyAccount { get; set; }
        /// <summary>
        /// 支付账号商家代码
        /// </summary>
        [CsvColumn(Title = "Merchant Account")]
        public string MerchantAccount { get; set; }
    }
    CsvFileDescription csvFileDescription = new CsvFileDescription(3);
    List<CSVModel> item1List = new CsvHelper().Read<OrderTransaction.Adyen.CSVModel>("/test.csv", csvFileDescription);

     

  • 相关阅读:
    JavaScript 闭包
    JavaScript for循环
    JavaScript switch语句
    JavaScript if...else 语句
    JavaScript流程控制语句脑图
    JavaScript比较和逻辑运算符
    JavaScript运算符
    记录一下获取浏览器可视区域的大小的js
    20181016记录一次前端布局
    20181015记录一个简单的TXT日志类
  • 原文地址:https://www.cnblogs.com/lxhbky/p/13711743.html
Copyright © 2011-2022 走看看