關於我

我的相片
用心思考、保持熱情,把工作上的經驗作分享與紀錄。希望能夠跟大家一起不斷的成長~

Oledb Export DataSet to Excel

同事遇到一個需求,須將Data匯出成已排版完成的Word檔,

成為一份電子書,給予User下載。還需要有封面、目錄、速查表等頁面。

最後同事決定,將Data彙整於DataTable中,

並將所有Data於DataTable中,將所有資料均排版完成。

原始資料如下圖,是一般常見的資料狀況:

擷取拷貝

經過編輯後,被排版成下圖,

擷取拷貝2

這樣的好處是,可以將此排版好的DataTable,

直接用套表的方式匯出,後段程式只需注意套表與字型等問題即可,不需再費心於排版上。

在製作目錄或速查表等需計算頁數之頁面時,也將簡單許多。

 

而今天的重點來了,因為需要修改此段排版程式,須加入其他商業邏輯。

但排版好的DataTable,我們又看不到,怎麼快速確定是否正確呢?!

有了這個念頭,便想到之前有找到過將DataTable匯出為Excel的參考範例

今天趕緊將此找到的範例程式記錄下來。方便下此再次瞭解使用。

 

程式碼如下:

public static void ExportDataSetToExcel(DataSet data, String excelFileName)
{
  System.IO.File.Delete(excelFileName);
  string strConnectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source="
  + System.IO.Path.GetDirectoryName(excelFileName) + @"\" + System.IO.Path.GetFileName(excelFileName)
  + @";Extended Properties='Excel 8.0;HDR=YES'";
  using (System.Data.OleDb.OleDbConnection objConn = new
  System.Data.OleDb.OleDbConnection(strConnectionString))
  using (System.Data.OleDb.OleDbCommand cmd = new
  System.Data.OleDb.OleDbCommand("", objConn))
  {
    objConn.Open();
    foreach (DataTable dt in data.Tables)
    {
      cmd.CommandText = "CREATE TABLE [" + dt.TableName + "] (";
      String valueNames = "(";
      Boolean first = true;
      foreach (DataColumn dc in dt.Columns)
      {
        if (!first)
        {
          cmd.CommandText += ",\r\n";
          valueNames += ", ";
        }
        cmd.CommandText += " [" + dc.ColumnName + "] NVARCHAR(100)";
        valueNames += " [" + dc.ColumnName + "]";
        first = false;
      }
      cmd.CommandText += ")";
      valueNames += ")";
      cmd.ExecuteNonQuery();
      foreach (DataRow dr in dt.Rows)
      {
        String values = "(";
        first = true;
        foreach (DataColumn dc in dt.Columns)
        {
          if (!first)
            values += ", ";
          values += " '" + dr[dc] + "'";
          first = false;
        }
        values += ")";
        cmd.CommandText = "INSERT INTO [" + dt.TableName + "$] " +
        valueNames + " VALUES " + values;
        cmd.ExecuteNonQuery();
      }
    }
  }
}

而上方兩張截圖,就是用此方式,將DataTable匯出程Excel後,

開啟之結果。用此方式快速許多。

最後,就完成了排版完成的Word檔案囉~~~

擷取拷貝3

這張報表(這算報表嗎?!)實在是不好寫,

也順便記錄下同事的Ideal,如果下次遇到,也可以參考。

這樣就可以將程式拆開,不會又要排版又要寫資料..又要計算頁次等一堆事情,

全擠在同一支程式裡,大大的增加了程式的可維護性囉~~

讚!!!

(順帶一提,同事的Word套表,是用Html方式產生套表的。)

使用 SharpZipLib 發生解壓時,壓縮檔毀損問題

上次有寫了一篇關於使用SharpZipLib的文章 Streaming a zip file over http in .net with SharpZipLib 

結果在客戶端實際使用時,當客戶下載zip檔案後,

使用Windows內建的compressed (zipped) Folders開啟解壓縮時,發現匯出現下方錯誤訊息!

擷取

 

在Google上搜尋了一下,查出發生的原因為,預設SharpZipLib使用的是Zip64格式

而Windows內建的compressed (zipped) Folders是不支援此格式的。

因此解決方法需要強制指定壓縮時,不使用Zip64格式。即可解決此問題。

加入程式碼:

zipOutput.UseZip64 = UseZip64.Off;

該段程式修改後如下:

byte[] buffer = new byte[1024 * 8];
using (ZipOutputStream zipOutput = new ZipOutputStream(stream))
{
  zipOutput.UseZip64 = UseZip64.Off;  //強制指定不使用Zip64格式壓縮,避免windows內建zip無法開啟
  foreach (string fileName in fileNames)
  {
    ZipEntry zipEntry = new ZipEntry(fileName.Substring(fileName.LastIndexOf('\\') + 1));
    zipOutput.PutNextEntry(zipEntry);
    using (FileStream fread = File.OpenRead(fileName))
    {
      StreamUtils.Copy(fread, zipOutput, buffer);
    }
  }
  zipOutput.Finish();
}

即可解決此問題了!!

Streaming a zip file over http in .net with SharpZipLib

今天因為專案需求,需要於網站上可以將多個檔案zip後,Popup下載視窗,讓User可下載檔案zip包。這個需求之前有做過的做法如下:
  1. 先將所有要zip的檔案zip至一個暫存的目錄中。
  2. 將zip檔讀入為byte[],再Response.binarywrite出該byte[]檔案。
  3. 再將暫存檔案刪除。

可是這樣的做法,多了一個暫存的動作。

實在不是個好的做法。

因此今天花了點時間,找到了一個參考Sample

以此Sample即可達成省去暫存zip檔的步驟。

  1. 將要壓縮的檔案,一個一個讀入,zip後放入Stream中。
  2. 直接將Stream於網頁output出來即可。

以下為實際完成的程式。

using System;
using System.Text;
using System.Web;
using System.Xml;
using System.Data;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Core;
using System.IO;
using System.Collections.Generic;
namespace VAT2005.Forms
{
  class Utility
  {
    /// <summary>
    /// 將多個檔案zip後,Response下載!
    /// </summary>
    /// <param name="context">HttpContext</param>
    /// <param name="fileNames">要zip的多個檔案完整路徑與檔名</param>
    /// <param name="outputfilename">要output之zip檔案檔名</param>
    public static void DownloadFilesZip(HttpContext context, List<string> fileNames, string outputfilename)
    {
      context.Response.ContentType = "application/x-zip-compressed";
      context.Response.AppendHeader("content-disposition", string.Format("attachment; filename={0}", outputfilename));
      context.Response.ContentEncoding = Encoding.Default;
      context.Response.Charset = "";
      //設定zip時,buffer的大小
      byte[] buffer = new byte[1024 * 8];
      using (ZipOutputStream zipOutput = new ZipOutputStream(context.Response.OutputStream))
      {
        //依序讀入要zip的檔案
        foreach (string fileName in fileNames)
        {
          //新增zip檔案
          ZipEntry zipEntry = new ZipEntry(fileName.Substring(fileName.LastIndexOf('\\') + 1));
          //放入OutputStream中
          zipOutput.PutNextEntry(zipEntry);
          //讀入file
          using (FileStream fread = File.OpenRead(fileName))
          {
            //將file(Stream)使用buffer zip後,放入zipOutput中
            StreamUtils.Copy(fread, zipOutput, buffer);
          }
        }
        zipOutput.Finish();
      }
      context.Response.Flush();
      //完成Stream寫出,讓User下載
      context.Response.End();
    }
  }
}
透過上方做法,即可直接將要zip的多個檔案,zip後,讓User下載!

當然,此zip做法是使用SharpZipLib,必須要referance才可使用!