目录
需求描述
详细需求分析
学习交流(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);的代码:
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);
-
-
复制代码 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博客
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |