• C#读取CSV文件

    2019-05-24 16:39:18
    C#读取CSV文件功能属性标签反射部分Csv读取的class读取文件读取title(字段名!)读取数据(values)将读取的字段名(title)和数据集合(二维数组)序列化结束语 功能 读取CSV文件并反射为对象实例 由于各个渠道得到的csv...

    功能

    1. 读取CSV文件并反射为对象实例
    2. 由于各个渠道得到的csv格式不同,此处使用的是office表格导出的csv文件
    3. 将读到的数据写入对象中,并返回出去
    4. 使用属性标签表示类中的属性是否都需要写入
    5. 可以写入的只能是字段

    属性标签

    做了两种属性

    1. 需要写入值,并修改名字
    	/// <summary>
        ///     表示需要写入value,并使用自定义name
        /// </summary>
        public class WriteValueAttribute : Attribute {
            //自定的name
            public string m_name;
            //属性信息,在反射时填充
            public PropertyInfo m_property;
    
            /// <summary>
            ///     初始化 <see cref="T:System.Attribute" /> 类的新实例。
            /// </summary>
            public WriteValueAttribute(string name) {
                m_name = name;
            }
        }
    

    2.不需要写入值

        /// <summary>
        ///     表示不需要写入value,如果没有这个属性标签,将会以属性名作为name
        /// </summary>
        public class NonWriteValueAttribute : Attribute { }
    

    3.不需要修改名字则不打标签

    加了WriteValueAttribute标签的,将会用设置的name
    加了WriteValueAttribute标签的,必须有setter,否则将会略过并报错
    加了NonWriteValueAttribute标签的,将不会被写入
    没有加标签的,如果有setter,将会写入,如果数据不存在,会报错
    没有加标签的,如果没有有setter,将会略过
    

    反射部分

    先上代码

        /// <summary>
        ///     反射泛型中的属性,只反射拥有setter的属性
        /// </summary>
        internal class Refect {
            /// <summary>
            ///     反射到的属性
            /// </summary>
            public List<PropertyInfo> Property;
            /// <summary>
            ///     拥有<see cref="WriteValueAttribute" />的属性标签
            /// </summary>
            public List<WriteValueAttribute> PropertyName;
    
            public Refect(Type type) {
                var ps        = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
                var infos     = new List<PropertyInfo>();
                var infoNames = new List<WriteValueAttribute>();
                foreach (var item in ps) {
                    if (item.GetCustomAttribute<NonWriteValueAttribute>() != null)
                        continue;
                    if (!item.CanWrite) {
                        if (item.GetCustomAttribute<WriteValueAttribute>() != null)
                            Debug.LogError(type.Name + "的属性" + item.Name + "没有setter");
                        continue;
                    }
    
                    infos.Add(item);
                    var att = item.GetCustomAttribute<WriteValueAttribute>();
                    if (att != null) {
                        att.m_property = item;
                        infoNames.Add(att);
                    }
                }
    
                Property     = infos;
                PropertyName = infoNames;
            }
        }
    

    反射到所需的属性后并不直接返回,而是保存起来.使这个类作为对象使用

    构造对象时获取所有共有属性

    var ps        = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
    

    然后循环数组根据标签获取需要的属性保存

    Csv读取的class

    读取文件

    读取文件时使用下面的API

    //fullName是文件名(包含路径),encoding是编码方式
    var lines = new List<string>(File.ReadLines(fullName, encoding));
    

    编码方式可以用utf-8,但是如果有中文的话可能会乱码.
    如果用office表格导出的csv,则显示中文需要使用gb2312

    var encoding = Encoding.GetEncoding("gb2312");
    

    读取title(字段名!)

    title对应字段名属性标签中设置的name
    这里遵循C#的命名规范,所以不会有特殊字符( , " \ 等)
    可以直接以,分割

    new List<string>(titleStr.Trim().Split(','));
    

    读取数据(values)

    1. 如果数据是字符串则会在两边添加一对""
    2. 字符串中有,的情况也需要考虑
    3. 读取到的数据将是二维数组,一行为一个对象
            private static List<List<string>> ReadValue(List<string> lines) {
                var resList = new List<List<string>>();
                foreach (var line in lines) {
                    var valueList = new List<string>();
                    var datas     = line.Split(',');
                    var queue     = new Queue<string>();
                    foreach (var data in datas)
                        if (queue.Count <= 0) {
                            if (data.StartsWith("\"")) {
                                if (data.EndsWith("\"") && !data.EndsWith("\"\"") && data.Length >= 2)
                                    valueList.Add(DelESC(data.Substring(1, data.Length - 2)));
                                else
                                    queue.Enqueue(data);
                            } else {
                                valueList.Add(data);
                            }
                        } else {
                            if (data.EndsWith("\"") && !data.EndsWith("\"\"")) {
                                queue.Enqueue(data);
                                valueList.Add(DelESC(GetStringByQueue(queue)));
                                queue.Clear();
                            } else {
                                queue.Enqueue(data);
                            }
                        }
    
                    resList.Add(valueList);
                }
    
                return resList;
            }
    

    foreach这个lines时,每个item就是一个对象(一行)

    先根据,分割,然后会出现问题,比如

    12,“a”“s”“d,fgh”

    将会被切割成三个字符串

    12–“a”“s”“d–fgh”

    字符串中的"因为被转义为了"",所以如果是一个",就是字符串的头尾
    此时使用队列处理
    处理后取出真正的字符串

            //从队列中拼接字符串并删去前后的<">
            private static string GetStringByQueue(Queue<string> queue) {
                var str = "";
                if (queue.Count <= 0)
                    return "";
                str += queue.Dequeue();
                for (var i = 0; queue.Count > 0; i++) str += "," + queue.Dequeue();
                str = str.Substring(1, str.Length - 2);
                return str;
            }
    

    此时的字符串还不是最终的,因为

    12–“a”“s”“d,fgh”

    这里的""是转义后的,所以需要处理一下

            //删去字符串中的转义,表格导出的csv中只有"被转义为""
            private static string DelESC(string str) {
                var count = 0;
                var cs    = new char[str.Length];
                for (var i = 0; i < str.Length; i++, count++) {
                    if (str[i] == '\"') i++;
                    cs[count] = str[i];
                }
    
                return new string(cs, 0, count);
            }
    

    将读取的字段名(title)和数据集合(二维数组)序列化

    序列化时需要知道是哪个类对吧?
    所以需要一个泛型或者Type,并且有无参构造

    //只是序列化的声明
    List<T> Serialize<T>(List<string> names, List<List<string>> values) where T : new()
    

    首先先进行反射这个类型

    var refect = new Refect(typeof(T));
    

    根据名字获取反射的属性信息
    根据PropertyInfo向对象写入值
    具体的方法如下

            //反射信息的缓存字典
            private static Dictionary<Type, Refect> m_cacheRefects;
            //根据属性和Type序列化这些数据
            //m_cacheRefects是一个缓存属性信息的字典,提前缓存了
            private static List<T> Serialize<T>(List<string> names, List<List<string>> values) where T : new()
            {
                var list = new List<T>();
                var type = typeof(T);
                if (!m_cacheRefects.ContainsKey(type))
                    throw new Exception("反射属性失败,字典中不存在");
                var refect = m_cacheRefects[type];
                var pros   = new List<PropertyInfo>();
                for (var i = 0; i < names.Count; i++) {
                    PropertyInfo info    = null;
                    var          proName = refect.PropertyName.Find(p => p.m_name == names[i]);
                    if (proName == null)
                        info = refect.Property.Find(p => p.Name == names[i]);
                    else
                        info = proName.m_property;
                    pros.Add(info);
                }
    
                for (var i = 0; i < values.Count; i++) {
                    var t = new T();
                    for (var j = 0; j < pros.Count; j++) SetValue(pros[j], t, values[i][j]);
                    list.Add(t);
                }
    
                return list;
            }
    

    结束语

    这里由于其他地方过来的csv文件转义处理可能不同

    比如"可能处理为\"而不是我的""

    所以需要适当地修改一下读取数据的那部分代码
    最后贴一下这个CsvHelper的源码

        /// <summary>
        ///     CSV文件读取类
        /// </summary>
        public sealed class CsvHelper {
            //反射信息的缓存字典
            private static Dictionary<Type, Refect> m_cacheRefects;
    
            /// <summary>
            ///     静态构造
            /// </summary>
            static CsvHelper() {
                m_cacheRefects = new Dictionary<Type, Refect>();
            }
    
            /// <summary>
            ///     读取文件
            /// </summary>
            /// <typeparam name="T">文件中存放的类型</typeparam>
            /// <param name="fullName">文件名(包含路径)</param>
            /// <param name="encoding">编码方式,中文可能是gb2312</param>
            /// <param name="firstNote">第一行是否为注解(比如把第一行作为中文注解,第二行才是属性名)</param>
            /// <returns>读取的对象集合</returns>
            public static List<T> ReadFile<T>(string fullName, Encoding encoding, bool firstNote = false) where T : new() {
                var typeT = typeof(T);
                //如果没有就反射并缓存反射信息 
                if (!m_cacheRefects.ContainsKey(typeT))
                    m_cacheRefects.Add(typeT, new Refect(typeT));
                //
                var lines = new List<string>(File.ReadLines(fullName, encoding));
                if (firstNote) {
                    lines.RemoveAt(0);
                }
                //
                var names = ReadTitle(lines[0]);
                lines.RemoveAt(0);
                var values = ReadValue(lines);
                //
                return Serialize<T>(names, values);
            }
    
            /// <summary>
            ///     提前反射需要的类型并缓存
            /// </summary>
            /// <typeparam name="T">类型</typeparam>
            public static void RefectType<T>() {
                RefectType(typeof(T));
            }
    
            /// <summary>
            ///     提前反射需要的类型并缓存
            /// </summary>
            /// <param name="t">类型</param>
            public static void RefectType(Type typeT) {
                //如果没有就反射并缓存反射信息
                if (!m_cacheRefects.ContainsKey(typeT))
                    m_cacheRefects.Add(typeT, new Refect(typeT));
            }
    
            //读取头部,即属性名
            private static List<string> ReadTitle(string titleStr) {
                return new List<string>(titleStr.Trim().Split(','));
            }
    
            //读取数据部分,此时不解析
            private static List<List<string>> ReadValue(List<string> lines) {
                var resList = new List<List<string>>();
                foreach (var line in lines) {
                    var valueList = new List<string>();
                    var datas     = line.Split(',');
                    var queue     = new Queue<string>();
                    foreach (var data in datas)
                        if (queue.Count <= 0) {
                            if (data.StartsWith("\"")) {
                                if (data.EndsWith("\"") && !data.EndsWith("\"\"") && data.Length >= 2)
                                    valueList.Add(DelESC(data.Substring(1, data.Length - 2)));
                                else
                                    queue.Enqueue(data);
                            } else {
                                valueList.Add(data);
                            }
                        } else {
                            if (data.EndsWith("\"") && !data.EndsWith("\"\"")) {
                                queue.Enqueue(data);
                                valueList.Add(DelESC(GetStringByQueue(queue)));
                                queue.Clear();
                            } else {
                                queue.Enqueue(data);
                            }
                        }
    
                    resList.Add(valueList);
                }
    
                return resList;
            }
    
            //根据属性和Type序列化这些数据
            private static List<T> Serialize<T>(List<string> names, List<List<string>> values) where T : new() {
                var list = new List<T>();
                var type = typeof(T);
                if (!m_cacheRefects.ContainsKey(type))
                    throw new Exception("反射属性失败,字典中不存在");
                var refect = m_cacheRefects[type];
                var pros   = new List<PropertyInfo>();
                for (var i = 0; i < names.Count; i++) {
                    PropertyInfo info    = null;
                    var          proName = refect.PropertyName.Find(p => p.m_name == names[i]);
                    if (proName == null)
                        info = refect.Property.Find(p => p.Name == names[i]);
                    else
                        info = proName.m_property;
                    pros.Add(info);
                }
    
                for (var i = 0; i < values.Count; i++) {
                    var t = new T();
                    for (var j = 0; j < pros.Count; j++) SetValue(pros[j], t, values[i][j]);
                    list.Add(t);
                }
    
                return list;
            }
    
            //从队列中拼接字符串并删去前后的<">
            private static string GetStringByQueue(Queue<string> queue) {
                var str = "";
                if (queue.Count <= 0)
                    return "";
                str += queue.Dequeue();
                for (var i = 0; queue.Count > 0; i++) str += "," + queue.Dequeue();
                str = str.Substring(1, str.Length - 2);
                return str;
            }
    
            //删去字符串中的转义,表格导出的csv中只有"被转义为""
            private static string DelESC(string str) {
                var count = 0;
                var cs    = new char[str.Length];
                for (var i = 0; i < str.Length; i++, count++) {
                    if (str[i] == '\"') i++;
                    cs[count] = str[i];
                }
    
                return new string(cs, 0, count);
            }
    
            /// <summary>
            ///     因为设置值时必须是同一类型,所以用这个来写入
            ///     将值中的数据赋值到obj中
            /// </summary>
            /// <param name="info">字段属性</param>
            /// <param name="obj">需要被赋值的对象</param>
            /// <param name="valObj">字段的值</param>
            public static void SetValue(PropertyInfo info, object obj, string val) {
                if (info.PropertyType == typeof(ushort))
                    info.SetValue(obj, string.IsNullOrEmpty(val) ? (ushort) 0 : ushort.Parse(val));
                if (info.PropertyType == typeof(short))
                    info.SetValue(obj, string.IsNullOrEmpty(val) ? (short) 0 : short.Parse(val));
                if (info.PropertyType == typeof(uint))
                    info.SetValue(obj, string.IsNullOrEmpty(val) ? (uint) 0 : uint.Parse(val));
                if (info.PropertyType == typeof(int))
                    info.SetValue(obj, string.IsNullOrEmpty(val) ? 0 : int.Parse(val));
                if (info.PropertyType == typeof(float))
                    info.SetValue(obj, string.IsNullOrEmpty(val) ? (float) 0 : float.Parse(val));
                if (info.PropertyType == typeof(bool))
                    info.SetValue(obj, string.IsNullOrEmpty(val) ? false : int.Parse(val) != 0);
                if (info.PropertyType == typeof(string))
                    info.SetValue(obj, val);
            }
        }
    
    展开全文
  • 在很多实际业务中,经常会有从外部CSV文件数据导入到系统里,更新数据库,或者更新云端Entity。 这个是非常简单的一个应用,具体也可以查看微软官方文档。 1. 安装Visula Studio,目前的最新版本是2019版,也可以...

    在很多实际业务中,经常会有从外部CSV文件数据导入到系统里,更新数据库,或者更新云端Entity。

    这个是非常简单的一个应用,具体也可以查看微软官方文档。

    1. 安装Visula Studio,目前的最新版本是2019版,也可以是旧的2017版,2015版都可以。

    2. 新建工程,建一个控制台.NET Framework的项目即可。

    3. 插入以下代码,注释部分有些日文,大家可以无视啊。不好意思,懒得修改了,不影响实际效果。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace csvread
    {
        class Program
        {
            static void Main(string[] args)
            {
    
                ReadCsv();
                Console.ReadKey();
    
            }
            static void ReadCsv()
            {
                try
                {
                    // csvファイルを開く
                    using (var sr = new System.IO.StreamReader(@"銀行振込情報.csv"))
                    {
                        // ストリームの末尾まで繰り返す
                        while (!sr.EndOfStream)
                        {
                            // ファイルから一行読み込む
                            string line = sr.ReadLine();
                            // 読み込んだ一行をカンマ毎に分けて配列に格納する
                            string[] values = line.Split(',');
                            // 出力する
                            for (int i = 0; i < values.Length; i++)
                            {
                                System.Console.Write("{0} ", values[i]);
                            }
                            System.Console.WriteLine();
                        }
                    }
                }
                catch (System.Exception e)
                {
                    // ファイルを開くのに失敗したとき
                    System.Console.WriteLine(e.Message);
                }
            }
        }
    }
    

    4. csv文件现在命名是“銀行振込情報.csv”、大家可以自己修改。

    编译完后,准备好csv文件,放入到代码工程的debug文件夹下,不然运行的时候会检出异常,由于文件找不到。

    csv文件内容大家就自己随便写。我这边是以下数据。

    Date	Name	Amount
    2019/5/25	Jack	30000
    2019/5/26	Mack	30001
    2019/5/27	Hack	30002
    2019/5/28	Sack	30003
    

    5. 输出结果:

    6. Debug确认中途变化的内容:

    第一行,i=0的时候,line和values数据的结果如下:

    第二行,i=0的时候,line和values数据的结果如下:

    第三行,i=0的时候,line和values数据的结果如下:

    第四行,i=0的时候,line和values数据的结果如下:

    第五行,i=0的时候,line和values数据的结果如下:

    7. 通过自己的Debug确认中间过程,对于程序的执行就有了更加清晰的理解。

    string line = sr.ReadLine(); //逐行读取csv文件文本,中间还会多出来‘,’,作为整体的字符串进行保存。

    string[] values = line.Split(','); //将中间的‘,’作为分界限隔离成字符串数据。

    8. 关于StreamReader Class的说明和使用可以查询微软.NET Framework

    https://docs.microsoft.com/zh-cn/dotnet/api/system.io.streamreader?view=netframework-4.8

     

    展开全文
  • C#读取CSV文件的方法

    2019-06-26 19:06:36
    在很多系统中,都需要读取csv文件,我在以前的一个项目中也遇到过要将csv文件中的数据读取到datatable中进行处理,下面的代码 是我以前写的将csv文件中的数据导入到DataTable中的方法,现在贴出来给大家分享: //...

    在很多系统中,都需要读取csv文件,我在以前的一个项目中也遇到过要将csv文件中的数据读取到datatable中进行处理,下面的代码

    是我以前写的将csv文件中的数据导入到DataTable中的方法,现在贴出来给大家分享:

    //GetCSVFile'S FileName and Data获取csv文件中数据,并将数据导入DataTable中

    // mycsvdt 用来装csv文件中数据的datatable,filepath是指csv文件的路径

    private bool OpenCSVFile(ref DataTable mycsvdt,string filepath)
            {
                string strpath = filepath; //csv文件的路径
                try
                {
                    int intColCount = 0;
                    bool blnFlag = true;

                    DataColumn mydc;
                    DataRow mydr;
                    
                    string strline;
                    string [] aryline;
                    StreamReader mysr = new StreamReader(strpath,System.Text.Encoding.Default);

                    while((strline = mysr.ReadLine()) != null)
                    {
                        aryline = strline.Split(new char[]{','}); 

                        //给datatable加上列名
                        if (blnFlag)
                        {
                            blnFlag = false;
                            intColCount = aryline.Length;
                            int col=0;
                            for (int i = 0; i < aryline.Length; i++)
                            {
                                col=i+1;
                                mydc = new DataColumn(col.ToString());
                                mycsvdt.Columns.Add(mydc);
                            }
                        } 

                        //填充数据并加入到datatable中
                        mydr = mycsvdt.NewRow();
                        for (int i = 0; i < intColCount; i++)
                        {
                            mydr[i] = aryline[i];
                        }
                        mycsvdt.Rows.Add(mydr);
                    }
                    return true;

                }
                catch (Exception e)
                {
                    
                   
                    throw (Stack.GetErrorStack(strpath+"读取CSV文件中的数据出错." + e.Message, "OpenCSVFile("));
                    return false;
                }
            }

    转载于:https://www.cnblogs.com/kevinGao/archive/2011/12/24/3175988.html

    展开全文
  • C#完美读取CSV

    2015-09-08 10:38:27
    C#读写CSV,一般情况下根据分隔符自动切分 但是特殊情况下,如表中有分隔符的语句,需要特殊解析 using System; using System.Collections.Generic; using System.IO; using System.Text; namespace ReadWriteCsv...

    C#读写CSV,一般情况下根据分隔符(最常用的是逗号分隔符)自动切分

    但是特殊情况下,如表中有分隔符的语句,需要特殊解析




    对应的文本内容:






    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    
    namespace ReadWriteCsv
    {
        /// <summary>
        /// Class to store one CSV row
        /// </summary>
        public class CsvRow : List<string>
        {
            public string LineText { get; set; }
        }
    
        /// <summary>
        /// Class to write data to a CSV file
        /// </summary>
        public class CsvFileWriter : StreamWriter
        {
            public CsvFileWriter(Stream stream)
                : base(stream)
            {
            }
    
            public CsvFileWriter(string filename)
                : base(filename)
            {
            }
    
            /// <summary>
            /// Writes a single row to a CSV file.
            /// </summary>
            /// <param name="row">The row to be written</param>
            public void WriteRow(CsvRow row)
            {
                StringBuilder builder = new StringBuilder();
                bool firstColumn = true;
                foreach (string value in row)
                {
                    // Add separator if this isn't the first value
                    if (!firstColumn)
                        builder.Append(',');
                    // Implement special handling for values that contain comma or quote
                    // Enclose in quotes and double up any double quotes
                    if (value.IndexOfAny(new char[] { '"', ',' }) != -1)
                        builder.AppendFormat("\"{0}\"", value.Replace("\"", "\"\""));
                    else
                        builder.Append(value);
                    firstColumn = false;
                }
                row.LineText = builder.ToString();
                WriteLine(row.LineText);
            }
        }
    
        /// <summary>
        /// Class to read data from a CSV file
        /// </summary>
        public class CsvFileReader : StreamReader
        {
            public CsvFileReader(Stream stream)
                : base(stream)
            {
            }
    
            public CsvFileReader(string filename)
                : base(filename)
            {
            }
    
            /// <summary>
            /// Reads a row of data from a CSV file
            /// </summary>
            /// <param name="row"></param>
            /// <returns></returns>
            public bool ReadRow(CsvRow row)
            {
                row.LineText = ReadLine();
                if (String.IsNullOrEmpty(row.LineText))
                    return false;
    
                int pos = 0;
                int rows = 0;
    
                while (pos < row.LineText.Length)
                {
                    string value;
    
                    // Special handling for quoted field
                    if (row.LineText[pos] == '"')
                    {
                        // Skip initial quote
                        pos++;
    
                        // Parse quoted value
                        int start = pos;
                        while (pos < row.LineText.Length)
                        {
                            // Test for quote character
                            if (row.LineText[pos] == '"')
                            {
                                // Found one
                                pos++;
    
                                // If two quotes together, keep one
                                // Otherwise, indicates end of value
                                if (pos >= row.LineText.Length || row.LineText[pos] != '"')
                                {
                                    pos--;
                                    break;
                                }
                            }
                            pos++;
                        }
                        value = row.LineText.Substring(start, pos - start);
                        value = value.Replace("\"\"", "\"");
                    }
                    else
                    {
                        // Parse unquoted value
                        int start = pos;
                        while (pos < row.LineText.Length && row.LineText[pos] != ',')
                            pos++;
                        value = row.LineText.Substring(start, pos - start);
                    }
    
                    // Add field to list
                    if (rows < row.Count)
                        row[rows] = value;
                    else
                        row.Add(value);
                    rows++;
    
                    // Eat up to and including next comma
                    while (pos < row.LineText.Length && row.LineText[pos] != ',')
                        pos++;
                    if (pos < row.LineText.Length)
                        pos++;
                }
                // Delete any unused items
                while (row.Count > rows)
                    row.RemoveAt(rows);
    
                // Return true if any columns read
                return (row.Count > 0);
            }
        }
    }


    测试方法:


    void WriteTest()
    {
        // Write sample data to CSV file
        using (CsvFileWriter writer = new CsvFileWriter("WriteTest.csv"))
        {
            for (int i = 0; i < 100; i++)
            {
                CsvRow row = new CsvRow();
                for (int j = 0; j < 5; j++)
                    row.Add(String.Format("Column{0}", j));
                writer.WriteRow(row);
            }
        }
    }
    
    void ReadTest()
    {
        // Read sample data from CSV file
        using (CsvFileReader reader = new CsvFileReader("ReadTest.csv"))
        {
            CsvRow row = new CsvRow();
            while (reader.ReadRow(row))
            {
                foreach (string s in row)
                {
                    Console.Write(s);
                    Console.Write(" ");
                }
                Console.WriteLine();
            }
        }
    }


    原文链接: http://www.codeproject.com/Articles/415732/Reading-and-Writing-CSV-Files-in-Csharp


    展开全文
  • C# 读取csv数据

    2019-04-29 16:58:17
    最近忙的一个项目中有对csv数据的操作,主要是读的问题,以为很简单,不就是数据按行读取后,用逗号来分隔吗! 刚开始确实也是这么做的,直到遇到了单元格中含有逗号的情况,就懵逼了。 举个栗子: 有这么一个...

    最近忙的一个项目中有对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;
    

    大致记录完成,方便以后自己查阅,也为有需要的童鞋,提供帮助,如果有兴趣就仔细研究递归部分代码,如有问题,还请指正,也希望还有更优化的方案。

    展开全文
  • C#文件流读取CSV文件

    2020-07-07 17:39:47
    文件流读取EXCEL
  • C# CSV文件读写

    2016-11-16 10:02:45
    CSV是一种通用的、相对简单的文件格式,最广泛的应用是在程序之间转移表格数据,而这些程序本身是在不兼容的格式上进行操作的。那么,C#如何读取和写入csv格式文件呢?
  • c#读取CSV格式文件

    2019-04-28 15:15:56
    using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; namespace XXG { class CSVReader ... static ...
  • C#读取.csv文件

    2018-03-21 22:42:20
    由于项目需要把.csv文件中的信息写到数据库中,NPOI处理.csv文件不太好使所以得换一种方法,最后找到了LumenWorks.Framework.IO这个好东西,可以很方便的满足我的需求,引用也很方便直接在NuGet中安装即可。
  • /// <summary>... /// 将CSV文件的数据读取到DataTable中 /// </summary> /// <param name="fileName">CSV文件路径</param> /// <returns>返回读取CSV数据的DataTa...
  • 1. csv文件路径为D:\test\test.csv ,(文件内的数据量很大) 2. A列作为标签列,其他列为数据列 3. 要求:根据输入的值,查找A列,然后将其相应的数据读出。 4. 例如:当输入2时,需要从表中读出第6至第9行的...
  • //读取内容 StringBuilder sbContent = new StringBuilder(); using (StreamReader sr = new StreamReader(Application.StartupPath + "/content.txt")) { string line; while ((line = sr.ReadLine()) !....
  • C# TXT CSV 文件读写

    2020-07-05 10:19:34
    c# 读写txt文件和 csv文件,只需一条语句,文件放在可执行文件的文件夹下
  • 国外比较著名的c#语言开发的csv文档读取类,能够快速的读取csv文档,可以把csv当成内存表进行操作
  • 运行环境:vs2010 Csv文件的读写,操作Csv文件,将dataGridView导出到CSV,加载CSV数据到DataGridView,包含对逗号的处理,内容中包含逗号也可以
  • http://blog.sina.com.cn/s/blog_7acc74e50100w4hp.html  int intColCount = 0;   bool blnFlag = true;   DataTable mydt = new DataTable("myTableName");
  • 使用C#读取csv文件的实例源码【201903】
  • 源文件下载地址:...为了方便在C#在对CSV中的操作,笔者进行了重新编写。此CSV类具有以下特点: 使用简单 只需要几行代码即可定义、访问和进行相应的读写操作。 功能完善 包括CS...
1 2 3 4 5 ... 20
收藏数 4,214
精华内容 1,685