【C#工具类】Excel接口(一)

10 篇文章 0 订阅

目录

需求描述

具体需求分析

学习交流(Bug待解决)

Debug代码(写代码的过程,逐渐完善的过程)

参考资料

扩展阅读


 需求描述

用C#生成两个函数

1. 盲读Excel (Excel文件名)
读取所有单元格的数据,并输出Json 
如:{[{"X":"2","Y":"4","V":"第2行第4列的值"}, {"X":"3","Y":"8","V":"第3行第8列的值"}]}


2. 按指定参数读取Excel (Excel文件名,Json参数)

{ "固定单元格读取":[
        {"X":"2","Y":"4","V":"第2行第4列的值"},
      {"X":"3","Y":"8","V":"第3行第8列的值"}    ],
  "二位表格读取":[
        {"二维表格名称":"表格1","列头行数":"1","X1":"2","X2":"6","Y1":"4","Y2":"","行结束方式":"固定列动态行单元格为具体文本","行结束识别X":"1","行结束文本":""},
        {"二维表格名称":"表格1","列头行数":"1","X1":"2","X2":"6","Y1":"4","Y2":"","行结束方式":"行无数据","行结束识别X":"","行结束文本":""}
    ]
}


"单元格":[
        {"X":"2","Y":"4","V":"第2行第4列的值"},
      {"X":"3","Y":"8","V":"第3行第8列的值"}    ],
  "表格":[
        {"Name":"表格1",Data:[{"列1名":"1","列2名":"2"},{"列1名":"1","列2名":"2"}]},
        {"Name":"表格1",Data:[{"列1名":"1","列2名":"2"},{"列1名":"1","列2名":"2"}]}
    ]

具体需求分析

Function1.

input:EXCEL(Sheet)

output:内容转换成Json

Function2.

input:固定单元格 or 二位表格(固定单元格 and 二位表格)

output:单元格 and 表格

思路:

1.读取EXCEL

网上有两种方式:

第一种是安装AccessDatabaseEngine,思路:

1)根据Excel文件获取所有Sheet名称

2)获取每一个Sheet的内容组装dataTable

3)table转Json

第二种是利用Npoi读取excel,思路:

1)将excel文件中的内容读取出来,存放到DataSet中

2)将DataTable转换成对应的list对象

3)将list对象转换成json,传递到前端

2.Json转换

1)引用Newtonsoft.Json.dll

下载地址:https://www.newtonsoft.com/json

下载完成后,找到对应版本的dll,项目中直接引用即可。

还有另外一种下载方式,使用Nuget :打开vs工具 - NuGet程序包管理器 - 程序包管理器控制台,这时在VS的底部窗口出现命令行:pm>install-package newtonsoft.json 执行完,会提示下载在哪个位置,再从项目中引用即可。

2)json和List的转换,更多是考虑List<T> 

注:下面记录的是开发过程中遇到的一些情况,然后随手记了一部分核心代码,完整的DEMO贴在最后。

测试案例 (简单设计了两个表格内容)

学习交流(Bug待解决)

Form2

方式一
output==>读文件显示LIST在DGV中,然后用MESSAGEBOX显示Json返回结果。

0.27读出来是.27,但其他带小数的数字没影响。

可优化点1:方式一的返回参数其实就是方式二的【单元格】返回参数,所以这两个返回结果的实体类可以合并。(Demo已优化)

方式二

input==>{"X":"2","Y":"4","V":"第2行第4列的值"},{ "X":"3","Y":"8","V":"第3行第8列的值"}

1)C#默认从0开始,(2,4)其实在系统中对应的是(3,5)并且还需要考虑是否会存在越界

2)需要格式化输入参数,关于最后一个传参V是否赋值存疑(思考:有没有设定非必填参数的方法?存入后台可以设定not null或者null,但是前端传参似乎都是必填的)【通用方法】

输入(2,4)和(2,4,0)和(2,4,Null)是否应该判定为一致?

3)    {"二维表格名称":"表格1","列头行数":"1","X1":"2","X2":"6","Y1":"4","Y2":"","行结束方式":"固定列动态行单元格为具体文本","行结束识别X":"1","行结束文本":""}

“列头行数”私以为有三种情况:0-没有表头即默认第一行为列头;1-默认第一行为列头;N-跳过多行,从第N行开始读取EXCEL内容

范围:从X1:Y1至X2:Y2(给的参考数据里Y2默认为空,但三个参数也确实可以确定范围)

行结束方式:行无数据(这个是具体输入的文字还是怎么决定的呢?)

行结束识别X:具体文本中某个字符?比如逗号空格之类

行结束文本:给的参考数据是空,所以具体逻辑不太清楚(在网上有参考了部分资料,但是好像还都没有细化到这个程度)

待完善点:其实主要是因为我对这个Input的理解还不够清晰,所以先默认表名称,开始表头和表格范围都是必填项,后面3个参数待优化补充。(NPOI中其实也都有提供相关属性)

4) 固定单元格 or 二位表格  还是 固定单元格 and 二位表格 ?

固定单元格 or 二位表格 :二种方式任选其一,固定单元格 的格式可以选取多个,并不仅限于两个(List允许上限范围内都可以查询)同时查询时也存在允许输入任一种或者两种(需要检验输入内容是否冲突)或者完全不选任何一种默认全读。

固定单元格 and 二位表格 : 将 固定单元格 限定为两个,然后作为 二位表格 中的范围条件(这种思路开发起来更简单,但是从参考Input中并没有发现关联的关系,所以后续可以作为 可优化点4

output==>读表格名称时默认显示的是Table1,Table2这样的,其实私以为返回1和Sheet1这样的更合理一些。(定义的DataTable dt,然后取的dt.TableName;)

==》关于获取到表名1和Sheet 的方式,可以利用NPOI中的方法(类似下面的思路,Demo已优化)

  NPOI.SS.UserModel.ISheet st;

  var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
  var wk=new  new XSSFWorkbook(fs);//2007之后版本的excel
  
  //获取读取的Sheet表的索引
  st = wk.GetSheetAt(0);

  MessageBox.Show(st.SheetName); //Sheet表名

LIST绑定DGV,因为LIST泛型走了一点弯路,暂时也没想到更好的处理方式(上图是所有的数据)然后绑定DGV的写法疑似存在一定局限性(中间切换的过程是通过MessageBox控制的,然后目前只能单一的绑定List,没法直接绑定实体类)效果如下:

 

对应代码:

            ExcelToJSON tolist = new ExcelToJSON();

            List<Result> list = tolist.ImportExcelResult(strFilePath);

            JavaScriptSerializer serializer = new JavaScriptSerializer();
            string jsonData = serializer.Serialize(list);
            MessageBox.Show(jsonData);


            foreach(Result rs in list)
            {
                foreach (单元格Item cell in rs.单元格)
                {
                    this.dataGridView1.DataSource = new BindingSource(new BindingList<单元格Item>(rs.单元格), null);
                    //MessageBox.Show("单元格Item");
                }
                MessageBox.Show(" 单元格Item => 表格Item.DataItem ");

                foreach (表格Item sheet in rs.表格)
                {
                    foreach (DataItem dataitem in sheet.Data)
                    {
                        this.dataGridView1.DataSource = new BindingSource(new BindingList<DataItem>(sheet.Data), null);
                        //MessageBox.Show("DataItem");
                    }
                }

            }

可优化点2:目前两个方式的返回结果是合在一起的返回的,理论上还可以优化精简成泛型。

可优化点3:目前是进入目录选择相应的EXCEL文件,然后回传相关数据。其实还可以只提供目录,由程式自动遍历找到所有的EXCEL文件。(思考:此处的文件过滤也可以做成下拉选项,除EXCEL是否还可以对CSV,TXT,DOC等文件进行不同的操作呢?)

Debug代码(写代码的过程,逐渐完善的过程)

1.DATATABLE转换JSON

思考:读文件显示表头,如何默认过滤第一行标头?

            string strFilePath, strFileName;

            strFilePath = FilePathHelper.SelectFile(null);
            strFileName = textBox2.Text;
            if (string.IsNullOrEmpty(strFileName))
            {
                strFileName = " ";
            }
            ExcelToJSON ImportExcel = new ExcelToJSON();

            var excelData = ImportExcel.ImportExcelToDataSet(strFilePath); //遍历DataSet
            if (excelData.Tables.Count < 1)
            {
               //...
            }
            foreach (DataTable dt in excelData.Tables)
            {
                //按Sheet读取Table内容(JSON,默认会带上列名)
                ExcelToJSON tojson = new ExcelToJSON();
                string rs = tojson.ToJson(dt);
                MessageBox.Show(rs);
            }

因为想找 TableName 写的一段带参数名称的输出,然而并没有找到。 

            string strFilePath, strFileName;

            strFilePath = FilePathHelper.SelectFile(null);
            strFileName = textBox2.Text;
            if (string.IsNullOrEmpty(strFileName))
            {
                strFileName = " ";
            }
            ExcelToJSON ImportExcel = new ExcelToJSON();

            var excelData = ImportExcel.ImportExcelToDataSet(strFilePath); //遍历DataSet
            if (excelData.Tables.Count < 1)
            {
               //...
            }
            foreach (DataTable dt in excelData.Tables)
            {
                //按Sheet读取Table内容(会带上格式)
                DataContractJsonSerializer serializer = new DataContractJsonSerializer(dt.GetType());
                using (MemoryStream ms = new MemoryStream())
                {
                    serializer.WriteObject(ms, dt);
                    StringBuilder sb = new StringBuilder();
                    sb.Append(Encoding.UTF8.GetString(ms.ToArray()));
                    MessageBox.Show(sb.ToString());
                }
            }

最后在NPOI读取EXCEL时将对应表名赋值给table,最后还是用dt.TableName读到了相应表名。

优化代码: table.TableName = sheet.SheetName; //Sheet表名 

 

2.没有套用INPUT的OUTPUT方式二( 先依照方式一做的output,直接根据选择的文件名返回所有数据)

 function2事件:

        private void button2_Click(object sender, EventArgs e)
        {

            string strFilePath, strFileName;

            strFilePath = FilePathHelper.SelectFile(null);
            strFileName = textBox2.Text; //先默认不填
            if (string.IsNullOrEmpty(strFileName))
            {
                strFileName = " ";
            }
            


            ExcelToJSON tolist = new ExcelToJSON(); 

            List<Result> list = tolist.ImportExcelResult(strFilePath);

            JavaScriptSerializer serializer = new JavaScriptSerializer();
            string jsonData = serializer.Serialize(list);
            MessageBox.Show(jsonData);

            /*
            foreach(Result rs in list)
            {
                foreach (单元格Item cell in rs.单元格)
                {
                    this.dataGridView1.DataSource = new BindingSource(new BindingList<单元格Item>(rs.单元格), null);
                    //MessageBox.Show("单元格Item");
                }
                MessageBox.Show(" 单元格Item => 表格Item.DataItem ");

                foreach (表格Item sheet in rs.表格)
                {
                    foreach (DataItem dataitem in sheet.Data)
                    {
                        this.dataGridView1.DataSource = new BindingSource(new BindingList<DataItem>(sheet.Data), null);
                        //MessageBox.Show("DataItem");
                    }
                }

            }
            */
           


        }

ExcelToJSON中ImportExcelResult(strFilePath);的代码: 

        #region DataTable内容转成Result(只选择文件即可返回两种结果)
        public List<Result> ImportExcelResult(string filePath)
        {


            List<Result> result = new List<Result>();


            var excelData = ImportExcelToDataSet(filePath);                //遍历DataSet
            if (excelData.Tables.Count < 1)
            {               
                return result;
            }
            foreach (DataTable dt in excelData.Tables)
            {
                按Sheet读取Table内容(JSON,默认会带上列名)
                //ExcelToJSON tojson = new ExcelToJSON();
                //string rs = tojson.ToJson(dt);
                //MessageBox.Show(rs);

                按Sheet读取Table内容(会带上格式)
                //DataContractJsonSerializer serializer = new DataContractJsonSerializer(dt.GetType());
                //using (MemoryStream ms = new MemoryStream())
                //{
                //    serializer.WriteObject(ms, dt);
                //    StringBuilder sb = new StringBuilder();
                //    sb.Append(Encoding.UTF8.GetString(ms.ToArray()));
                //    MessageBox.Show(sb.ToString());
                //}

                Result rs = new Result();

                List<单元格Item> item = new List<单元格Item>();              


                List<表格Item> sheet = new List<表格Item>();
                表格Item bit = new 表格Item();

                bit.Name = dt.TableName;


                foreach (DataRow dr in dt.Rows)
                {

                    List<DataItem> data = new List<DataItem>();                    

                    List<string> columnName = new List<string>();  //实例化一个参数集合
                    foreach (DataColumn dataColumn in dt.Columns)
                    {
                        columnName.Add(dataColumn.ColumnName);
                    }

                    for (var i = 0; i < dr.ItemArray.Length; i++)
                    {
                        单元格Item it = new 单元格Item();

                        DataItem di = new DataItem();
                        di.col_X = columnName[i]; //DataItem集合中添加键值

                        //验证是否包含特殊字符
                        if (dr.ItemArray[i].ToString() != "" && ValidateSymbol(dr.ItemArray[i].ToString()) == true)
                        {
                            it.X = "0";
                            it.Y = "0";
                            it.V = "0";
                        }
                        else
                        {                        

                            if (dr.ItemArray[i].ToString() != "")
                            {
                                it.X = dt.Rows.IndexOf(dr).ToString();
                                it.Y = i.ToString();
                                it.V = dr.ItemArray[i].ToString();                              
                                
                            }                          
                                                 
                        }
                        
                        item.Add(it);       
                        rs.单元格 = item;

                        di.col_Y = dr.ItemArray[i].ToString();
                        data.Add(di);
                    }
                    
                    bit.Data=data;
                }


                sheet.Add(bit);
                rs.表格=sheet;

                result.Add(rs);

            }        

            
            return result;
        }
        #endregion

3.转换方式二Input的JSON格式

输入的是实体类,传参时传入实体类,转换json格式放在工具类中还是在输入界面更合适?(textBox.Text->List<CellItem>->Input->json解析后使用)思考:可否写一个通用的转换方法?

 将1,3赋值给 单元格List 

           string inputValue = textBox1.Text.Trim(); //"1,3" 
           inputValue = inputValue.Replace(",",",");//替换中文状态的逗号

           Input inparam = new Input();

            //固定单元格
            List<CellItem> cs = new List<CellItem>();
            //{"X":"2","Y":"4","V":"第2行第4列的值"},{ "X":"3","Y":"8","V":"第3行第8列的值"}
            List<string> inputlist = new List<string>(inputValue.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)); //去除中间的空格
            CellItem ci = new CellItem();    
            ci.X = inputlist[0];
            ci.Y = inputlist[1];
            //ci.V = "";//Input时要不要赋值,我的理解是输入固定单元格,输出时返回这个单元格所对应的数据
            cs.Add(ci);
            inparam.CellItem=cs;

输入参数应该请使用者如何输入?目前先手输数组,类似(1,3),默认参数V不传;但是存在C#从0开始计数,实际习惯从1开始数EXCEL单元格的情况,并且由使用者输入的参数还有可能存在中英文符号,不加括号等等各种格式(仅查一个单元格时肯定大部分人都不喜欢加括号,就算key括号也会存在()<>{}并且全角半角的输入法区别)。思考:可否通过正则或者其他方式单独写一个处理方法让input格式更规范统一?(思考:可否用正则取出了括号中间的单元格数组)

网上有找到过一些正则截取括号中间内容的写法,但是处理起连续的()好像一直不太得劲,后续有精力再研究一下,目前用了比较暴力的原始截取方法。

            string inputValue = "(1,3,1),(1,4,5)";
            //string inputValue ="(1,3),(1,4)";

            // var str=  Regex.Match(inputValue, @"(\([0-9]+,[0-9]+\))");//1,3

            int length = inputValue.Length - 1;
            int firstLeft = inputValue.IndexOf("(");
            int firstRight = inputValue.IndexOf(")")-1;
            int arr = firstRight - firstLeft;
            string str2 ;

            while (length > 0) //10
            {
                //结束位置 减 1 再减 开始位置 获取中间位置数
                str2=inputValue.Substring(inputValue.IndexOf("(") + 1, arr);//参数1:开始位置加1 参数2:长度:中间位置数
                MessageBox.Show(str2);//这里就是我想要的()中间的数据
                inputValue = inputValue.Remove(firstLeft, firstRight+2>length?length:firstRight+2);
                firstLeft = inputValue.IndexOf("(");
                firstRight = inputValue.IndexOf(")") - 1;
                arr = firstRight - firstLeft;
                length = inputValue.Length - 1;
            }

转换JSON格式的方法:

        public static string Obj2Json<T>(T data)
        {
            try
            {
                DataContractJsonSerializer serializer = new DataContractJsonSerializer(data.GetType());
                using (MemoryStream ms = new MemoryStream())
                {
                    serializer.WriteObject(ms, data);
                    return Encoding.UTF8.GetString(ms.ToArray());
                }
            }
            catch
            {
                return null;
            }
        }

4.方式二的Input表格读取范围

1)通过 固定单元格 决定 二位表格 选取范围(就是上面的 可优化点4)

【固定单元格】对应的实体类在本次Project中多次用到,所以顺手就写了这种方式

但是通过上图可知我这里还有一个BUG:

对于没有读取的栏位,比如ABEFG,在单元格读取时在DGV中显示成了空白,并不是我最初设想的直接只返回两行的情况。有试过在读取Table栏位时只读取第C列和第D列,然而二维表格读取的分支里,赋值时会出现找不到对应列的情况。所以最后就变成了上述效果。

参考代码:


            string inputValue = textBox1.Text.Trim(); //"1,3" 
            inputValue = inputValue.Replace(",",",");//替换中文状态的逗号
            //通过遍历inputValue获取具体的单元格
            //inputValue = inputValue.Replace("(", "").Replace(")","").Replace("(", "").Replace(")", "");//去除所有(),默认中间也会key逗号,遍历每2-3个元素为固定单元格


           //把List集合转换为json字符串
            JavaScriptSerializer serializer = new JavaScriptSerializer();

            Input inparam = new Input();

            //固定单元格
            List<CellItem> cs = new List<CellItem>();


            //"(1,3),(1,4)"
            int length = inputValue.Length - 1;
            int firstLeft = inputValue.IndexOf("(");
            int firstRight = inputValue.IndexOf(")") - 1;
            int arr = firstRight - firstLeft;
            string str2;

            List<string> resList = new List<string>();

            while (length > 0) //10
            {
                //结束位置 减 1 再减 开始位置 获取中间位置数
                str2 = inputValue.Substring(inputValue.IndexOf("(") + 1, arr);//参数1:开始位置加1 参数2:长度:中间位置数
                resList.Add(str2);
                inputValue = inputValue.Remove(firstLeft, firstRight + 2 > length ? length : firstRight + 2);
                firstLeft = inputValue.IndexOf("(");
                firstRight = inputValue.IndexOf(")") - 1;
                arr = firstRight - firstLeft;
                length = inputValue.Length - 1;
            }


            foreach (string i in resList.ToArray())
            {
                //{"X":"2","Y":"4"},{ "X":"3","Y":"8"}
                //{"X":"2","Y":"4","V":"第2行第4列的值"},{ "X":"3","Y":"8","V":"第3行第8列的值"}
                List<string> cist = new List<string>(i.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)); //去除中间的空格

                CellItem ci = new CellItem();
                ci.X = cist[0];
                ci.Y = cist[1];
                //ci.V = "";//Input时要不要赋值,我的理解是输入固定单元格,输出时返回这个单元格所对应的数据

                cs.Add(ci);

            }
            inparam.CellItem=cs;


            //二位表格
            //{ "二维表格名称":"表格1","列头行数":"1","X1":"2","X2":"6","Y1":"4","Y2":"","行结束方式":"固定列动态行单元格为具体文本/行无数据","行结束识别X":"1","行结束文本":""},
            List<SheetItem> ss = new List<SheetItem>();

            SheetItem si = new SheetItem();
            si.Sheet = strFileName;//Sheet1
            si.Col = "1";
            si.X1 = cs[0].X;
            si.X2 = cs[1].X;
            si.Y1 = cs[0].Y;
            si.Y2 = cs[1].Y;
            si.Row = "";
            si.Row_X = "";
            si.Row_End = "";
            ss.Add(si);
            inparam.SheetItem = ss;

            //格式化传参JSON Input
            string jsonInput = serializer.Serialize(inparam);
            MessageBox.Show(jsonInput);

            
            

        public DataSet ImportExcelToDataSet(string filePath,Input inparam)
        {            
            //表名             inparam.SheetItem[0].Sheet
            //列头行数         inparam.SheetItem[0].Col
            //范围            inparam.SheetItem[0].X1/X2/Y1/Y2
            //行结束方式
            //行结束识别
            //行结束文本

            DataSet ds = new DataSet();
            IWorkbook workbook;
            string fileExt = Path.GetExtension(filePath).ToLower();
            try
            {
                using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                {
                    if (fileExt == ".xlsx")
                    {
                        workbook = new XSSFWorkbook(fs);//2007之后版本的excel
                    }
                    else
                    {
                        workbook = new HSSFWorkbook(fs);//2003版本的excel
                    }

                   
                    //for (int a = 0, b = workbook.NumberOfSheets; a < b; a++)
                    //{
                        //获取读取的Sheet表的索引
                        ISheet sheet = workbook.GetSheet(inparam.SheetItem[0].Sheet);
                        DataTable table = new DataTable();
                        table.TableName = sheet.SheetName; //Sheet表名 


                    int firstrow;

                    if (inparam.SheetItem[0].Col == "1" || inparam.SheetItem[0].Col == "0")
                    {
                        //将第一行的文本作为列名 inparam.SheetItem[0].Col
                        firstrow = sheet.FirstRowNum;
                    }
                    else
                    {
                        firstrow = Convert.ToInt16( inparam.SheetItem[0].Col)-1;
                       
                    }
                    IRow headerRow = sheet.GetRow(firstrow);
                    int cellCount = headerRow.LastCellNum;

                    for (int i = sheet.FirstRowNum; i < cellCount; i++)
                    {
                            DataColumn column;
                            object obj = GetValueType(headerRow.GetCell(i));
                            if (obj == null || obj.ToString() == string.Empty)
                            {
                                column = new DataColumn("Columns" + i.ToString());
                            }
                            else
                            {
                                column = new DataColumn(obj.ToString());
                            }
                            table.Columns.Add(column);
                       
                     }

                    //读取第一行下面的数据,将他们作为数据行存储
                    //for (int i = (sheet.FirstRowNum + 1); i <= sheet.LastRowNum; i++)  //首列名称不保留

                    //excel单元格默认+1,所以此处设定-1 
                    int begini = Convert.ToInt32(inparam.SheetItem[0].X1) - 1;
                    int endi = Convert.ToInt32(inparam.SheetItem[0].X2) - 1;
                    int beginj = Convert.ToInt32(inparam.SheetItem[0].Y1) - 1;
                    int endj = Convert.ToInt32(inparam.SheetItem[0].Y2) - 1;

                    for (int i =begini ; i <= endi; i++)  
                    {
                            IRow row = sheet.GetRow(i);
                            if (row == null || row.GetCell(0) == null || row.GetCell(0).ToString().Trim() == "")
                            {
                                // 如果遇到第一个空行,跳出本次循环,继续向下读取                              
                                continue;
                            }
                            DataRow dataRow = table.NewRow();
                            for (int j = beginj; j <= endj; j++)
                            {
                                if (row.GetCell(j) != null)
                                {
                                    dataRow[j] = row.GetCell(j).ToString();
                                }
                            }
                            table.Rows.Add(dataRow);
                     }

                        ds.Tables.Add(table);

                   // }
                    workbook = null;
                    return ds;
                }
            }
            catch (Exception ex)
            {
                return ds;
            }
        }

2)通过3个参数决定选取范围(需要另外判断范围从小到大)

DEMO源码(包含我测试的两个excel文件)

附:Form1是我拿来测试截取单元格的小玩意儿~包含最基础的循环和正则,可以当作小彩蛋吧~

参考资料:

C#读取EXCEL文件并生成Json

C#将List集合转换为json字符串_c#list转换成json-CSDN博客

C#如何将DataTable转换成List类

json与DataTable相互转换

C#中把Datatable转换为Json的5个代码实例_c# html 源码 获取table转json-CSDN博客

unity C#将excel解析为json

c#读写EXCEL的几种方法

c#使用NPOI读写EXCEL

C# 使用 NPOI 库读写 Excel 文件_c# npoi读取excel数据-CSDN博客

 C# dataGridView绑定List数据-CSDN博客

winform DataGridView绑定List<T>类型数据_winfrom t-CSDN博客

C#中WinForm制作点击"选择文件"按钮选择Excel文件, 并读取Excel内容到DataTable_winform click事件从文件读取列表-CSDN博客

C# 通过行和列直接读取Excel中数据的方法_c#获取excel每一列已使用单元格数量-CSDN博客

c#中List<Object>取出对应的值----dynamic_c# 获取 object 转 dynamic-CSDN博客

在C#中使用正则表达式提取括号中的内容_c# 正则表达式 匹配括号中内容-CSDN博客

C#从字符串中批量截取中间字符串_c# 获取字符串中所有td中间的内容-CSDN博客

C#获取动态key的json对象的值_c# 获取json对象中的值和key-CSDN博客

扩展阅读:

JSON压缩转义 - 站长工具

C#中如何将List<自定义>转为Json格式 及相关函数-DataContractJsonSerializer_c# 数组转json-CSDN博客

使用NPOI读取Excel到DataTable_npoi读取excel到datable并设置列数据类型-CSDN博客

java-读取Excel文件,自定义读取固定行、列(不区分xls、xlsx)_java excel自定义行列-CSDN博客 NPOI使用手册-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值