C#_.net core 3.0自定义读取.csv文件数据_解决首行不是标题的问题_Linqtocsv改进
linqtocsv文件有不太好的地方就是:无法设置标题的行数,默认首行就是标题,这不是很尴尬吗? 并不是所有的csv文件严格写的首行是标题,下面全是数据,我接受的任务就是读取很多.csv报表数据,里面就有很多前几行是说明性内容,下面才是标题和数据。为了更好的解决这个问题,自己写吧...
本博客没有照搬linqtocsv全部源码,保留了主要功能,并对其优化,为我所用,哈哈...
下面是主要代码:
1-主文件CsvHelper:
这里在独自解析数据的时候,遇到了很多坑:
a-遇到数据含有分隔符的问题的解决办法,代码已经包含了
b-遇到了解析源文档数据时,未指定字符编码时,部分数据丢失导致csv文件个别行数据解析异常的问题,针对该问题,就是老老实实把读取文件时加了字符编码的参数进去,默认UTF-8。
- using Microsoft.Extensions.Logging;
- using PaymentAccountAPI.Helper;
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Reflection;
- using System.Text;
- namespace PaymentAccountAPI.CSV
- {
- 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>( * );
- T t = null;
- int currentRawIndex = ;
- 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 = ;
- int yhEndIndex = ;
- string yhText = null;
- do
- {
- yhBeginIndex = StringHelper.GetIndexOfStr(rawValue, "\"", );
- yhEndIndex = StringHelper.GetIndexOfStr(rawValue, "\"", );
- yhText = rawValue.Substring(yhBeginIndex, (yhEndIndex - yhBeginIndex + ));
- string newYHText = yhText.Replace("\"", "").Replace(fileDescription.SeparatorChar.ToString(), "{分隔符}");
- rawValue = rawValue.Replace(yhText, newYHText);
- } while (rawValue.Contains("\""));
- }
- rawValueArray = rawValue.Split(fileDescription.SeparatorChar);
- t = new T();
- foreach (var fieldMapper in fieldMapperDic)
- {
- propertyInfo = fieldMapper.Value.PropertyInfo;
- propertyValue = rawValueArray[fieldMapper.Key - ];
- if (!string.IsNullOrEmpty(propertyValue))
- {
- try
- {
- if (isExistSplitChart && propertyValue.Contains("{分隔符}"))
- {
- propertyValue = propertyValue.Replace("{分隔符}", fileDescription.SeparatorChar.ToString());
- }
- TypeHelper.SetPropertyValue(t, propertyInfo.Name, propertyValue);
- }
- catch (Exception e)
- {
- this._Logger.LogWarning(e, $"第{currentRawIndex + 1}行数据{propertyValue}转换属性{propertyInfo.Name}-{propertyInfo.PropertyType.Name}失败!");
- continue;
- }
- }
- }
- 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(, path.LastIndexOf('\\'));
- }
- else
- {
- fileDirectoryPath = path.Substring(, 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 = ;
- int tIndex = ;
- using (StreamWriter streamWriter = new StreamWriter(path, false, fileDescription.Encoding))
- {
- do
- {
- try
- {
- rawValue = "";
- #if DEBUG
- if (currentRawIndex % == )
- {
- this._Logger.LogInformation($"已写入文件:{path},数据量:{currentRawIndex}");
- }
- #endif
- if (currentRawIndex >= fileDescription.TitleRawIndex)
- {
- //清空数组数据
- for (int i = ; 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 - ] = 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 - ] = formatValue;
- }
- }
- }
- rawValue = string.Join(fileDescription.SeparatorChar, rawValueArray);
- }
- rawValueBuilder.Append(rawValue + "\r\n");
- }
- catch (Exception e)
- {
- this._Logger.LogWarning(e, $"(异常)Excel第{currentRawIndex+1}行,数据列表第{tIndex + 1}个数据写入失败!rawValue:{rawValue}");
- throw;
- }
- currentRawIndex++;
- } while (tIndex < dataCount);
- streamWriter.Write(rawValueBuilder.ToString());
- streamWriter.Close();
- streamWriter.Dispose();
- }
- }
- }
- }
- }
2-CSV映射类特性:
- using System;
- namespace PaymentAccountAPI.CSV
- {
- /// <summary>
- /// Csv文件类特性标记
- /// </summary>
- [System.AttributeUsage(System.AttributeTargets.Field | System.AttributeTargets.Property, AllowMultiple = false)]
- public class CsvColumnAttribute : System.Attribute
- {
- internal const int defaultTitleIndex = Int32.MaxValue;
- /// <summary>
- /// 标题
- /// </summary>
- public string Title { get; set; }
- /// <summary>
- /// 标题位置(从0开始)
- /// </summary>
- public int TitleIndex { get; set; }
- /// <summary>
- /// 字符输出格式(数字和日期类型需要)
- /// </summary>
- public string OutputFormat { get; set; }
- public CsvColumnAttribute()
- {
- Title = "";
- TitleIndex = defaultTitleIndex;
- OutputFormat = "";
- }
- public CsvColumnAttribute(string title, int titleIndex, string outputFormat)
- {
- Title = title;
- TitleIndex = titleIndex;
- OutputFormat = outputFormat;
- }
- }
- }
3-CSV文件描述信息类:
- using System.Text;
- namespace PaymentAccountAPI.CSV
- {
- public class CsvFileDescription
- {
- public CsvFileDescription() : this()
- {
- }
- 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>
- /// 分隔符(默认为(,),也可以是其他分隔符如(\t))
- /// </summary>
- public char SeparatorChar { get; set; }
- /// <summary>
- /// 标题所在行位置(默认为0,没有标题填-1)
- /// </summary>
- public int TitleRawIndex { get; set; }
- }
- }
4-映射类获取关系帮助类:
- using System.Collections.Generic;
- using System.Linq;
- using System.Reflection;
- namespace PaymentAccountAPI.CSV
- {
- /// <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>();
- List<PropertyInfo> tPropertyInfoList = typeof(T).GetProperties().ToList();
- CsvColumnAttribute csvColumnAttribute = null;
- foreach (var tPropertyInfo in tPropertyInfoList)
- {
- csvColumnAttribute = (CsvColumnAttribute)tPropertyInfo.GetCustomAttribute(typeof(CsvColumnAttribute));
- if (csvColumnAttribute != null)
- {
- fieldMapperList.Add(new FieldMapper
- {
- PropertyInfo = tPropertyInfo,
- CSVTitle = csvColumnAttribute.Title,
- CSVTitleIndex = csvColumnAttribute.TitleIndex,
- OutputFormat = csvColumnAttribute.OutputFormat
- });
- }
- }
- return fieldMapperList;
- }
- }
- }
5-其他扩展类:
- namespace PaymentAccountAPI.Helper
- {
- public class StringHelper
- {
- /// <summary>
- /// 获取字符串中第strPosition个位置的str的下标
- /// </summary>
- /// <param name="text"></param>
- /// <param name="str"></param>
- /// <param name="strPosition"></param>
- /// <returns></returns>
- public static int GetIndexOfStr(string text, string str, int strPosition)
- {
- int strIndex = -;
- int currentPosition = ;
- if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(str) && strPosition >= )
- {
- do
- {
- currentPosition++;
- if (strIndex == -)
- {
- strIndex = text.IndexOf(str);
- }
- else
- {
- strIndex = text.IndexOf(str, strIndex + );
- }
- } while (currentPosition < strPosition);
- }
- return strIndex;
- }
- }
- }
最后就是将CsvHelper注入到单例中,就可以使用了...
C#_.net core 3.0自定义读取.csv文件数据_解决首行不是标题的问题_Linqtocsv改进的更多相关文章
- C#使用Linq to csv读取.csv文件数据
前言:今日遇到了一个需要读取CSV文件类型的EXCEL文档数据的问题,原本使用NPOI的解决方案直接读取文档数据,最后失败了,主要是文件的类型版本等信息不兼容导致.其他同事有使用linq to csv ...
- matlab读取csv文件数据并绘图
circle.m(画二维圆的函数) %该函数是画二维圆圈,输入圆心坐标和半径%rectangle()函数参数‘linewidth’修饰曲线的宽度%'edgecolor','r',edgecolor表示 ...
- python读取csv文件数据绘制图像,例子绘制天气每天最高最低气温气象图
- C#使用Linq to csv读取.csv文件数据2_处理含有非列名数据的方法(说明信息等)
第一篇博客为:https://www.cnblogs.com/lxhbky/p/11884474.html 本文主要是为了解决上面博客遗留的一个含有不规范数据的一种方法,目前暂时没有从包里发现可以从第 ...
- VB 读取csv文件数据
Public adoConn As New ADODB.Connection Private Sub csv() adoConn.ConnectionString = "Driver={Mi ...
- php 生成读取csv文件并解决中文乱码
csv其实是文本文件,但是里面的内容是利用逗号分隔的. 1. 生成csv文件 function new_csv($arr) { $string=""; foreach ($arr ...
- NET Core 2.0 自定义
ASP.NET Core 2.0 自定义 _ViewStart 和 _ViewImports 的目录位置 在 ASP.NET Core 里扩展 Razor 查找视图目录不是什么新鲜和困难的事情,但 _ ...
- ASP.NET Core 5.0 中读取Request中Body信息
ASP.NET Core 5.0 中读取Request中Body信息 记录一下如何读取Request中Body信息 public class ValuesController : Controller ...
- VB6.0 读取CSV文件
最近做了一个Upload文件的需求,文件的格式为CSV,读取文件的方法整理了一下,如下: 1.先写了一个读取CSV文件的Function: '读取CSV文件 '假设传入的参数strFile=C:\Do ...
随机推荐
- Mysql梳理-关于索引/引擎与锁
前言 最近突发新型肺炎,本来只有七天的春节假期也因为各种封锁延长到了正月十五,在家实在闲的蛋疼便重新研究了一下Mysql数据库的相关知识,特此总结梳理一下.本文主要围绕以下几点进行: 1.Mysql的 ...
- 创建dynamics CRM client-side (十四) - Web API
Xrm.WebApi 是我们做前端开发不可不缺少的内容. Xrm.WebApi 分为online和offline online: 可以实现和服务器的CRUD交互 offline: 多用于mobile ...
- 爬虫之协程,selenium
1.什么是代理?代理和爬虫之间的关联是什么? 2.在requests的get和post方法常用的参数有哪些?分别有什么作用?(四个参数) - url headers parmas/data proxi ...
- ios---设置UITabBarController的字体颜色和大小
+(void)load{ NSMutableDictionary *attr3=[NSMutableDictionary dictionary]; attr3[NSForegroundColorAtt ...
- Kafka系列1:Kafka概况
Kafka系列1:Kafka概况 Kafka是当前分布式系统中最流行的消息中间件之一,凭借着其高吞吐量的设计,在日志收集系统和消息系统的应用场景中深得开发者喜爱.本篇就聊聊Kafka相关的一些知识点. ...
- springIOC源码接口分析(二):ConfigurableBeanFactory
一 继承功能 1 SingletonBeanRegistry接口 此接口是针对Spring中的单例Bean设计的.提供了统一访问单例Bean的功能,类中定义了以下方法: 2 HierarchicalB ...
- Springboot | @RequestBody 接收到的参数对象属性为空
背景 今天在调试项目的时候遇到一个坑,用Postman发送一个post请求,在Springboot项目使用@RequestBody接收时参数总是报不存在,但是多次检查postman上的请求格式以及项目 ...
- Spring(五)核心容器 - 注册 Bean、BeanDefinitionRegistry 简介
目录 前言 正文 1.BeanDefinitionRegistry 简介 2.registerBeanDefinition 方法注册 Bean 最后 前言 上篇文章我们对 BeanDefinition ...
- HDU 1251 统计难题 (Trie树模板题)
题目链接:点击打开链接 Problem Description Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单 ...
- BZOJ2326 [HNOI2011]数学作业(分块矩阵快速幂)
题意: 定义函数Concatenate (1 ..N)是将所有正整数 1, 2, …, N 顺序连接起来得到的数,如concatenate(1..5)是12345,求concatenate(1...n ...