凪瀬さんのWebからExcel出力のためのソリューションは?が元ネタです。
Mr.TさんのWebからExcel吐き出しも元ネタです。
※だいぶ以前のエントリに今さらトラックバックして申し訳御座いません。
業務系Webシステムを構築していると確かに「Excelで出力して欲しい」と言う要望は多々あります。
その様な場合、多くの場合はMr.Tさんと同じくHTMLを使用する方法でExcelファイルを作成して参りました。
HTMLを使用する方法には以下の特徴があります。
- サーバーにExcelをインストールする必要が無い。
- Excel 2000以降でのみ開く事が出来る。
- 1ファイル(ブック)当たり、1シートのみ。
- マクロや画像を含められない。
しかしながら、現場の要望では1つのファイル(ブック)に複数のシートを含めたいと言う要望は多々あります。
その場合に私が代替として使用しているのはHTML形式ではなくXMLスプレッドシート形式です。
※XMLを用いる方法は凪瀬さんがご紹介されている方法の一つですね。
XMLスプレッドシートを使用する方法には以下の特徴があります。
- サーバーにExcelをインストールする必要が無い。
- Excel 2003以降でのみ開く事が出来る。
- 1ファイル(ブック)当たり、複数シートに対応。
- マクロや画像を含められない。
以上の方法はWebサーバー内にExcelのライセンスや他社ミドルウェアを要せず、比較的簡単にExcelファイルを作成出来るのですが、マクロや画像を含めたい時やExcel 2000以前で複数シートを作成したいと言う要望には対応出来ません。
その様な場合に私が使用しているのはOLEです。
OLEを使用してExcelファイルを作成する事は、「ExcelのファイルをOLEデータベースとして扱う」と言うイメージで、以下の特徴があります。
- サーバーにExcelをインストールする必要が無い。
- テンプレートとなるファイルをサーバー内に配置しておく必要がある。
※テンプレートはExcel 97-2003形式(*.xls)とする事。
- Excel 97でも開く事が出来る。
- 1ファイル(ブック)当たり、複数シートに対応。
- マクロや画像を含められる。
OLEを使用する方法をご存知の方も多いかもしれませんが、一応以下にサンプルコードを載せておきます。
Imports System.Data.Common
Imports System.IO
Partial Public Class WebForm
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Me.Load
'テンプレートファイルを取得する
'※ASP.NETにのアクセス権に注意する事
Dim image As Byte()
Using readStream As New FileStream("C:\TemplateBook.xls", FileMode.Open), _
reader As New BinaryReader(readStream)
readStream.Position = 0
image = reader.ReadBytes(CInt(readStream.Length))
reader.Close()
End Using
'ファイルをTempディレクトリに書き出す
Dim tempFileName As String = Path.GetTempFileName
Using writeStream As New FileStream(tempFileName, FileMode.OpenOrCreate), _
writer As New BinaryWriter(writeStream)
writer.Write(image)
writer.Close()
End Using
'ファイルのDataシートにデータを埋め込む
'※Dataシート行目のA列、B列にそれぞれCode、Nameと入力しておく事
Dim connectionString As String = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & tempFileName & ";" & _
"Extended Properties=""Excel 8.0;HDR=YES;"""
Dim factory As DbProviderFactory = DbProviderFactories.GetFactory("System.Data.OleDb")
Using connection As DbConnection = factory.CreateConnection()
connection.ConnectionString = connectionString
connection.Open()
Using command As DbCommand = connection.CreateCommand()
command.CommandText = "INSERT INTO [Data$] ([Code],[Name]) VALUES('A','123')"
command.ExecuteNonQuery()
End Using
connection.Close()
End Using
'作成したファイルを返却する
Using readStream As New System.IO.FileStream(tempFileName, IO.FileMode.Open), _
reader As New System.IO.BinaryReader(readStream)
readStream.Position = 0
Response.AddHeader("Content-Type", "application/vnd.ms-excel")
Response.AddHeader("Content-Disposition", "attachment;filename=Test.xls")
Response.BinaryWrite(reader.ReadBytes(CInt(readStream.Length)))
reader.Close()
End Using
'一時ファイルを削除する
File.Delete(tempFileName)
'レスポンス終了
Response.End()
End Sub
End Class
サンプルはC:\にTemplateBook.xlsと言うテンプレートファイルを配置している事を前提としています。
テンプレートファイルにはDataシートを用意し、先頭行(ヘッダ行)にCodeおよびNameと言う文字を入力しておくことで、それらをCode列、Name列と認識させています。(接続文字列内にHDR=YESとありますが、これはシートにヘッダ行が存在する事を宣言しています。)
この方法はHTMLやXMLと異なり、表形式のシートに値を挿入するだけの事しか出来ません。
従い帳票の代替えとして使用する為には関数等を用い、「出力帳票イメージのシート」に対して「OLE経由で値をセットしたデータシート」から値を参照させる必要があります。(VBAを用いてWorkbookのOpen時に加工しても良いでしょう。)