zoukankan      html  css  js  c++  java
  • 多表导出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也可以实现,不过具体的还没有测试过。

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

  • 相关阅读:
    如何选择RabbitMQ的消息保存方式?
    一次Flannel和Docker网络不通定位问题
    flannel
    vsftp设置不同用户登录ftp的根目录不同
    nginx反向代理服务器获取不到端口的问题的解决办法
    RabbitMQ 内存控制 硬盘控制
    -bash: fork: Cannot allocate memory
    redis info
    nginx第三方模块---nginx-sticky-module的使用(基于cookie的会话保持)
    Haproxy的三种保持客户端会话保持方式
  • 原文地址:https://www.cnblogs.com/gcr1314/p/2850658.html
Copyright © 2011-2022 走看看