- - PR -
ADO.NET-OLE接続によるExcel出力について
投稿者 | 投稿内容 | ||||
---|---|---|---|---|---|
|
投稿日時: 2008-04-03 21:31
ASP.NETにて、ADO.NET-OLE接続によるExcel出力を行っています。(VS2005)
少ないデータの場合は問題なく完了するのですが 多いデータになると以下の問題が発生します。 実際にはExcelに出力されていないのに処理が完了し その直後のファイル読み取り処理で 「別のプロセスで使用されているため、プロセスはファイル 'C:\test.xls' にアクセスできません。 」エラーの発生。 上記は、まだExcel書き込み中のため、ファイルアクセス時にファイルを 開けず、エラーになるようです。 調べてみると仕様で、OLEによる書き込みは非同期で書き込むそうですが これを回避する方法はありますでしょうか。 参考までにソースは以下になります。 protected void Button1_Click(object sender, EventArgs e) { DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.OleDb"); using (DbConnection con = factory.CreateConnection()) { con.ConnectionString = String.Format("Provider=Microsoft.Jet.OLEDB.4.0; Data Source={0}; Extended Properties=\"Excel 8.0;HDR=YES;\" ", @"C:\test.xls"); con.Open(); using (DbTransaction tran = con.BeginTransaction()) { for (int i = 0; i < 500; i++) { DbCommand cmd = con.CreateCommand(); cmd.Transaction = tran; cmd.CommandText = "update [Sheet1$A1:D1000] set A=? where row = " + (i + 1); DbParameter para = cmd.CreateParameter(); para.Value = "a"; cmd.Parameters.Add(para); cmd.ExecuteNonQuery(); } tran.Commit(); } if (con != null) { con.Close(); } } Response.ContentType = "application/octet-stream"; Response.AppendHeader("Content-Disposition", "inline; filename=" + @"C:\test.xls"); // attachment/inline Response.WriteFile(@"C:\test.xls"); Response.End(); } 通常、こんな回避をする。あるいはそれは仕様だからどうしようもない など、ご意見頂けたらと思います。 [ メッセージ編集済み 編集者: ひんしつ 編集日時 2008-04-03 21:32 ] | ||||
|
投稿日時: 2008-04-03 22:20
ASP.NET ですよね?で、ユーザ アクションの、ボタン クリック イベント内で、やっているんですよね?
もう一つボタンを置いて、そのクリック イベントで、Sleep(6 * 1000) (6分)とかやってみてください。3分ほどで返ってきますから。 あなたが作っているのは、ASP.NET、ウェブ アプリケーションだということを、常に意識してください。これは、デスクトップ アプリケーションとは違います。同じような作り方ができますが、違うものです。デスクトップ アプリケーションとは、違う作法があります。 今回、あなたはその「違う作法」に引っかかったわけです。ウェブにリクエストを出して、長い間ページが更新されない。さて、どうしますか? 解決方法の一つは、こんな感じ→ASP.NET 1.1 長い処理中に「お待ちください」画面を表示する<wankuma.com> リクエストには、、、忘れた。何秒か以内にレスポンスを返してあげてください。 それから、ドライブのルートにものを書いて、それをダウンロードさせるのは止めましょう。これは、デスクトップ アプリケーションでも同じ。それに、複数のリクエストが同時にあった場合のことも考えましょう。 | ||||
|
投稿日時: 2008-04-03 23:49
ご返信ありがとうございます。
実は、ASP.NETですけど 実際は、Webサービスで実行し、クライアントはWindowsフォームです。 クライアント側から、このWebサービスは非同期実行で実行されます。 なので、ご心配頂いたところは大丈夫かと思います。 掲示したソースは、テストコードのため、ドライブのルートに とりあえず置いています。実際は、正しい場所に置かれます。 説明がいろいろと足りなくてすいません。 問題は、OLEでのExcel出力にあります。 しかしなぜ、わざわざASP.NETでサンプルを書いたかというと コンソールアプリとは異なる動作をしたためです。 コンソールアプリだと、30秒で終わる処理が、ASP.NETだと現状5分かかってしまいました 。 おそらくAsp.netのプロセスが残っているため、OLEによる出力が遅延しているのでは?と推測しています。 [ メッセージ編集済み 編集者: ひんしつ 編集日時 2008-04-04 08:39 ] | ||||
|
投稿日時: 2008-04-07 01:31
いまだ、前進していませんが、これまでにわかったことを
追記します。 http://www.canalian.com/workshop/access/JetCache.html ちょっと古いですが、↑によると >書込み時には、implicit transactionでは遅延(非同期)書込み、 >explicit transactionでは、遅延を生じない同期書込みが行われるようになっ >ています。これも、レジストリで設定されており、前者は ImplicitCommitSync = no、 >後者はUserCommitSync = yesという設定です。 >マルチユーザー環境などで、書き込み遅延が発生しては困るときには、 >同期書き込みを利用します。同期書き込みを行なうには、BeginTrans 〜 CommitTrans >という、明示的なトランザクションを利用します。 とあります。 もともと、非同期書き込みをサポートしていて、同期書き込みする場合は 明示的なトランザクションを使用すること。らしいですが BeginTransaction、Commitを行っても非同期で実行されているようです。 | ||||
|
投稿日時: 2008-04-09 21:58
少し変なことがわかったのでご報告します。
まったく同じコードの OLEによるExcel出力をNUnitから行うと成功しますが コンソールアプリから実行するとだめです。 コンソールアプリから実行するとすべて出力されていないExcelファイルが 出力されます。 途中までは書かれているのですが、途中で終わってしまったようなExcelが出力されます。 このNunitから実行した場合と、コンソールでは何か違うのでしょうか。 実行後の後処理?待ちうけ?それともスレッドの作り方? なにかご存知でしたら、ご助言ください。 | ||||
|
投稿日時: 2008-04-11 15:39
すっかり独り言状態ですが、
NUnitから実行すれば成功するのは気のせいだったようです。 ただ、コンソールプログラムに変更してSTAThread属性を指定することで 成功する確立があがりました。(OLEを使用する場合は必須?) しかし、まだ20〜30回に1度は、途中までしか書かれていない Excelが出力されます。 あと、もうひとつ、実験を行いました。 上記コンソールプログラムの最後に、Excelに出力した値を OLEで読み込む処理をいれて、書き込まれているかの確認を行いました。 すると、チェック結果は書かれていたが、実際に出力されたExcelには かかれてないという現象が発生。 これでは、やっぱりいつ書き込みが終了したのかわからないという状況のようです。 | ||||
|
投稿日時: 2009-03-05 16:31
この件について情報をお持ちの方、いらっしゃいますでしょうか?
書込み処理は正常終了するが、データが書き込まれていないことがまれに発生し 困っています。 | ||||
|
投稿日時: 2009-03-05 20:45
OLEでExcelに書き込むという選択をしないので、 気になったことを何点かだけ。 その前に、ちょっと整理させてもらいますが、 現状としては、コンソールアプリケーションに変更したが、 途中までしか出力されない事がある。 でいいですか? STAThreadはCOMのためにあった方がいいでしょうね。 途中までかかれない現象の場合にパターンは見いだせませんか? 出力量が多いとか。 ログの出力を試みたことは? (例外が起きていた場合は気づける作りですか?) 元々はWebサービスに組み込んでいたようですが、そこからプロセス作って 実行させているのであれば、どのユーザで実行されせているかとか。 あと気になる点では、 Commandにもusing句を使ってみる CommandがDisposeされる前にpara.clearを呼んでみる ぐらいでしょうか あまり参考にはならないかもしれませんが。 |