在做邮件群发器时,会将未发送列表中的邮件地址进行Excel导出保存,在日后群发时导入继续发送的功能。
该邮件群发器是以xml作为存储介质,开始的思路是想把xml数据以流的形式输出在内存中,提供客户下载。可是不知道怎么操作。去问同事,同事告诉我生成一个静态文本,让其下载时直接下载该文本就行,答非所问。无奈之下之后继续Google,中文搜索关键字不靠谱,被迫只能使用英文关键字(winform SaveFileDialog),还是老外从来都不会让我失望。
从中找到一篇标题为《Win Form: SaveFileDialog》的文章,该文章解决了困扰我一早上的问题。对于其中的代码进行修改,已经达到我所需要的目的.
在使用中发现StreamWriter中文乱码的问题,解决方案详情请参照StreamWriter 构造函数。
下边贴出具体实现代码:
private void ToExcel() { SaveFileDialog dlg = new SaveFileDialog(); /**************** * 这里需要说明下"所有文件(*.*)|*.*"配置是成对出现的,不然程序运行时会报如下错误: * "提供的筛选器字符串无效。筛选器字符串必须包含筛选器的说明,后跟竖线(|)和筛选模式。不同筛选选项的字符串还必须以竖线分隔。例如:“文本文件(*.txt)|*.txt|所有文件(*.*)|*.*”" ****************/ dlg.Filter = "所有文件(*.*)|*.*|Excel2003(*.xls)|*.xls|Excel2003以上版本(*.xlsx)|*.xlsx"; dlg.Title = "导出Excel文件"; dlg.FilterIndex = 2;//索引从1开始 //是否检查文件是否存在 dlg.CheckPathExists = true; if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK && dlg.FileName.Length > 0) { StreamWriter streamWriter = new StreamWriter(dlg.FileName, false, Encoding.GetEncoding("GB2312")); //"\t"代表换一列 streamWriter.Write("收件人\t企业名称"); //注意:streamWriter.NewLine等价于"\r\n"代表换行的意思 streamWriter.Write(streamWriter.NewLine); //streamWriter.Write("\r\n"); streamWriter.Write("[email protected]\r\n"); streamWriter.Write("[email protected]\r\n"); streamWriter.Write("[email protected]\r\n"); streamWriter.Close(); } }
在实际的应用中,上述方法只适合生成文本文件(txt)。此处生成的Excel实际上并不是真正意义上的Excel文件,只是把txt后缀名改成xls的文本文件而已,因此对其进行读取等操作是非常麻烦的。但是要直接生成真正意义上的Excel很麻烦,至今未找到好的解决方案。只晓得Dev组件里封装好的功能是不需要任何模板,就可以动态生成Excel的。具体机制没有源码不得而知。大家一般常用的方法就是读取一个现成的模板然后对其进行CRUD的操作,然后让客户保存。这种方法是我最不喜欢使用的,可是为赶项目又不得不去使用。毕竟在工作中用户看的是你能不能在规定的时间内做出他要东西,而不是耗费到他不能接受的时间给他一个你自认为是好的产品。反正用户只是要一个下载功能而已。程序如何好如何差的执行,跟他们没有半毛钱的关系。这不是他们所关注的。
下边贴出通过模板具体实现的导入导出Excel的代码,具体实现原理就是通过OleDbConnection类来实现,可以简单的理解为是操作数据库。不过Excel的第一行类似于数据库中的列名罢了。操作过数据库的人对于下列代码不会感到陌生。
导出Demo:
SaveFileDialog dlg = new SaveFileDialog(); dlg.Filter = "所有文件(*.*)|*.*|Excel2003(*.xls)|*.xls|Excel2003以上版本(*.xlsx)|*.xlsx"; dlg.Title = "导出Excel文件"; dlg.FilterIndex = 2;//索引从1开始 dlg.FileName = "SaveMailAddress.xls"; //是否检查文件是否存在 dlg.CheckPathExists = true; if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK && dlg.FileName.Length > 0) { #region 读取Excel模板 给其添加行数据 核心代码 //模板路径 string filePathTemplate = workDir + "data" + Path.DirectorySeparatorChar + "ImportExportTemplate.xls"; //记得要拷贝模板文件,否则CRUD操作会直接针对原模板进行操作 File.Copy(filePathTemplate, dlg.FileName, true); //连接Excel字符串 string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + dlg.FileName + ";Extended Properties='Excel 8.0;'"; //如下代码跟操作数据库是一个概念 using (OleDbConnection conn = new OleDbConnection(strConn)) { conn.Open(); OleDbCommand Cmd = new OleDbCommand("", conn); foreach (string add in listMailAddress.Items) { //执行SQL语句 Cmd.CommandText = "insert into [Sheet1$] ([收件人],[企业名称]) values ('" + add + "','')"; Cmd.ExecuteNonQuery(); } //使用using如下关闭代码可以省略 //conn.Close(); } #endregion
导入Demo:
OpenFileDialog dlg = new OpenFileDialog(); dlg.Filter = "Excel 2003(*.xls)|*.xls|Excel 2003以上版本(*.xlsx)|*.xlsx|所有文件(*.*)|*.*"; dlg.Title = "导入Excel文件"; if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK && dlg.FileName.Length > 0) { //获取全部数据 using (OleDbConnection conn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + dlg.FileName + ";Extended Properties='Excel 8.0;'")) { conn.Open(); OleDbCommand cmd = new OleDbCommand("select * from [Sheet1$]", conn); OleDbDataReader r = cmd.ExecuteReader(); listMailAddress.Items.Clear(); while (r.Read()) { listMailAddress.Items.Add(r[0].ToString());//索引代表列 } //conn.Close(); } }
Excel格式为:
注意的是"收件人","企业名称"均为列名,并且要放在Excel的第一行
A | B | C | D | E | F | G | |
1 | 收件人 | 企业名称 | |||||
2 | |||||||
3 |