多表导出csv功能

  最近公司需求做一个直接根据数据库表导出csv的功能,要求可以多个表同时导入到一个csv文件里,通过查阅相关资料后,终于实现了该功能,期间也遇到过一些问题在此总结一二。

  首先为了要获得数据库的表数据,写了一个通用方法,代码如下:

 1  public static DataSet GetTableAll(List<string> tableAll)
 2         {
 3            
 4             using (SqlConnection conn = new SqlConnection(connectionString))
 5             {
 6                 DataSet ds = new DataSet();
 7                 foreach (string table in tableAll)
 8                 {
 9                     DataTable dt = new DataTable();  
10                     using (SqlDataAdapter da = new SqlDataAdapter("Select * from  " + table, conn))
11                     {
12                         da.Fill(dt);
13                     }
14                     ds.Tables.Add(dt);
15                 }
16                 return ds;
17             }
18         }

返回的是一个ds集合,参数用的是List集合,这样就可以返回需要导出的表的集合。调用方法代码如下:

            List<string> tableAll = new List<string>();
            tableAll.Add("tableName");
            tableAll.Add("tableName");
            DataSet tableName = CommonClass.GetTableAll(tableAll);    
       CSVUtility.GetCSV(tableName, this.Page, 文件名);

代码比较简单就不在赘述了。最后就是最重要的导出方法了,代码如下:

 public static void GetCSV(DataSet data, Page page,String fileName)
        {
            MemoryStream stream = new MemoryStream();
            foreach (DataTable dt in data.Tables)
            {
                string[] filedsToExport = new string[dt.Columns.Count];
                for (int i = 0; i < dt.Columns.Count; i++)
                {
                    filedsToExport[i] = dt.Columns[i].ColumnName;

                }
                GetCSV(filedsToExport, dt, stream);

            }
            page.Response.ContentType = "application/csv";
            page.Response.Clear();
            page.Response.Buffer = true;
            page.Response.ContentEncoding = Encoding.UTF8;
            page.Response.Charset = "UTF-8";
            page.Response.AddHeader("Content-Disposition", "attachment;filename=" + fileName);
            page.Response.Cache.SetCacheability(HttpCacheability.NoCache);
           //防止中文乱码
            page.Response.BinaryWrite(new byte[] { 0xEF, 0xBB, 0xBF });
            page.Response.BinaryWrite(stream.ToArray());
            page.Response.Flush();
            page.Response.End();
        }

上面方法也比较简单,就是注释下面那行代码必须加上,否则会出现中文乱码现象,因为csv是纯文本文件,有个BOM方式编码问题。在上面方法中还调用了一个方法,通过MemoryStream对象流把数据写入了内存,具体代码如下:

 private static void GetCSV(string[] filedsToExport, DataTable data, MemoryStream stream)
        {
            using (var sw = new StreamWriterX(stream, false))
            {
                for (int i = 0; i < filedsToExport.Length; i++)
                {
                    if (i != 0)
                    {
                        sw.Write(",");
                    }
                    sw.Write("\"");
                    sw.Write(filedsToExport[i].Replace("\"", "\"\""));
                    sw.Write("\"");
                }
                sw.Write("\n");

                foreach (DataRow row in data.Rows)
                {
                    for (int i = 0; i < filedsToExport.Length; i++)
                    {
                        if (i != 0)
                        {
                            sw.Write(",");
                        }
                        sw.Write("\"");
                        sw.Write(row[filedsToExport[i]].ToString()
                            .Replace("\"", "\"\""));
                        sw.Write("\"");
                    }

                    sw.Write("\n");

                }
                sw.WriteLine("****************************The End********************************");
            }

        }


        //防止Writer关闭的时候自动关闭数据流
        class StreamWriterX : StreamWriter
        {
            public StreamWriterX(Stream stream, Boolean closeable)
                : base(stream)
            {
                var fi = typeof(StreamWriter).GetField("closable", BindingFlags.Instance | BindingFlags.NonPublic);
                if (fi != null) fi.SetValue(this, closeable);
            }
        }

上面这个方法其实有几个地方需要讲述下,第一个就是write的时候要注意csv转换格式的问题,我在末尾的时候加了一个WriteLine,因为多个表数据写入到同一个csv的时候,需要区分表与数据字段(暂时需求),比较重要的是SreamWriterX这个类,因为在Writer关闭的时候会自动关闭数据流,导致程序出错。这个问题折腾了好久,最后通过高人指导才算解决了这个问题,有人说通过重写Disponse也可以实现,不过具体的还没有测试过。

  虽然是一个小功能,期间尝试了各种方法,折腾了也挺蛮久的,不过确实收获了一些,所以分享出来与大家共勉,如果你有更好的解决方案,不吝赐教!

原文地址:https://www.cnblogs.com/gcr1314/p/2850658.html