- - PR -
ASPでのファイルダウンロード方法について
1
投稿者 | 投稿内容 | ||||
---|---|---|---|---|---|
|
投稿日時: 2008-09-12 19:13
ASPにてファイルのダウンロードサイトを構築したのですが、容量の大きいファイルのダウンロードが行えないという現象が発生しています。
(Response.BinaryWrite関数でエラーが発生。) 200MB以上のファイルは必ずダウンロードできず、100MB〜150MBのファイルはダウンロードできる時とできない時があります。 原因がわからないため、プログラムの変更を考えています。 以下のプログラム以外に、ダウンロードを行える方法はありますか? ■環境■ Windows2003 SP1 IIS 6.0 ASP(.netではないです。) ■ C:\WINDOWS\system32\inetsrv\MetaBase.xml 以下の設定値を変更 AspBufferingLimit="419430400" ■プログラムソース Sub writeBinary(strFileName) Dim Stream 'open file Set Stream = Server.CreateObject("ADODB.Stream") Stream.Open Stream.Type = 1 ' StreamTypeEnum の adTypeBinary Stream.LoadFromFile strFileName 'write header strDownloadFileName = Mid(strFileName, InStrRev(strFileName, "\")+ 1) Response.ContentType = "application/octet-stream" & vbCrLf & "Content-Disposition: attachment; filename=" & strDownloadFileName ' バイナリ型の Stream オブジェクトからを読み取って出力 Response.BinaryWrite Stream.Read '★イベントビューアではこの行でエラーがでている。 'エラー内容「メモリ不足. 必要なメモリを割り当てられません。。」 ' Stream を閉じる Stream.Close Set Stream = Nothing Response.Flush End Sub サーバのイベントビューアには、以下のメッセージが出ます。 (※ダウンロードできない場合に必ずエラーがでている訳でなはないのですが。。) ------------------------------------------------------------------ イベントの種類: エラー イベント ソース: Active Server Pages イベント カテゴリ: なし イベント ID: 5 日付: 2008/09/12 時刻: 17:54:10 ユーザー: N/A コンピュータ: XXXXX 説明: エラー : ファイル /xxx/xxx.inc 行 42 メモリ不足. 必要なメモリを割り当てられません。。 ------------------------------------------------------------------ イベントの種類: 警告 イベント ソース: W3SVC-WP イベント カテゴリ: なし イベント ID: 2262 日付: 2008/09/12 時刻: 17:54:15 ユーザー: N/A コンピュータ: XXXXX 説明: 次の理由のため、ISAPI 'C:\WINDOWS\system32\inetsrv\asp.dll' は自身が危険な状況であると報告しました : 'メモリ不足のため ASP に問題があります。'。 ------------------------------------------------------------------ ブラウザには以下のメッセージが表示されます。 「ページを表示できません 検索中のページには問題があるため表示できません。 」 [ メッセージ編集済み 編集者: kaz 編集日時 2008-09-12 19:14 ] | ||||
|
投稿日時: 2008-09-12 20:21
そのイベントログの状況だと、単純にメモリ不足に陥ってるように思います。
#そのあたりはパフォーマンスカウンタ等で調査してみていますでしょうか? 提示されているコードだと、レスポンスバッファがTrueであることが前提と思います。レスポンスバッファが有効な場合、Response.BinaryWriteの際にStreamからすべてのバイト配列をレスポンスバッファに読み、読み込み完了後にFlushする動きになると思います。 ですので、読み込むファイルサイズ分のメモリが最低限必要になる為、サイズが大きいとメモリの確保の失敗が発生するのではないかと推測します。 対処ですが……。 私自身そこまで気を遣わないといけない程のサイズのファイルをダウンロードさせようとしたことが無いので、幾分に推測含みになりますが、レスポンスバッファを使わないようにする(Response.Buffer=Falseにする)ことで、改善できるかもしれません。 | ||||
|
投稿日時: 2008-09-16 23:40
kiyokuraさん、回答ありがとうございます。
Response.Buffer=Falseに設定する方法を、以下のサイトを参考にテストしてみたところ、「Response.BinaryWrite」ではなく、「Stream.Read」でエラーが発生していることが判明しました。 Asp.netでは「Response.TransmitFile」関数でメモリに展開せずにできるとの記述があったので、調べているところです。 ■参照サイト http://cervi.jp/contents/2005/09/response_buffer.html ■プログラムソース Sub writeBinary(strFileName) Dim basp, data, bufferSize, offset, writeLen '-- バッファリングをオフ Response.Buffer = False '-- Basp21 を作成 Set basp = Server.CreateObject("Basp21") '-- データ読み込み 'open file Set Stream = Server.CreateObject("ADODB.Stream") Stream.Open Stream.Type = 1 ' StreamTypeEnum の adTypeBinary Stream.LoadFromFile strFileName data = Stream.Read ' data = basp.BinaryRead(Server.MapPath(strFileName)) '-- ContentType, Content-Length を設定 strDownloadFileName = Mid(strFileName, InStrRev(strFileName, "\")+ 1) Response.ContentType = "application/octet-stream" & vbCrLf & "Content-Disposition: attachment; filename=" & strDownloadFileName Response.AddHeader "Content-Length", ubound(data) + 1 '-- 1000 バイトづつ出力 bufferSize = 500 For offset = 0 To ubound(data) Step bufferSize writeLen = ubound(data) + 1 - offset If writeLen > bufferSize Then writeLen = bufferSize End If '-- バッファに出力 Response.BinaryWrite basp.MidB(data, offset, writeLen) Next '-- Basp21 を開放 Set basp = Nothing ' Stream を閉じる Stream.Close Set Stream = Nothing End Sub | ||||
|
投稿日時: 2008-09-17 01:58
きよくらです。
なるほど、これだと、ADODB.StreamのReadで結局変数に一気に読んでしまうので、ファイルサイズ分のメモリが必要になるのは変わらないですね……。 ということは、何らか読み込む時点でオフセット指定で読み込めれば解決しそうに思えます。 ADODB.Streamのリファレンスに上手くたどり着けないのでまた曖昧な記憶になるのですが、確かADODB.StreamだとReadメソッドに読み込みバイト数を指定できるオーバーロードがあった筈なので、それとオフセット位置を指定できるプロパティ(たぶんPositionだったと思います)を使えば、新しく提示されたコードの方法でいけるかもです。 #毎度、あやふやすみません。 | ||||
|
投稿日時: 2008-09-17 04:38
kiyokuraさん、回答ありがとうございます。
以下のプログラムで解決しました。 ありがとうございます。 ■プログラムソース Sub writeBinary(strFileName) Dim data, bufferSize, offset, writeLen, fso, fileSize '-- バッファリングをオフ Response.Buffer = False '-- データ読み込み 'open file Set Stream = Server.CreateObject("ADODB.Stream") Stream.Open Stream.Type = 1 ' StreamTypeEnum の adTypeBinary Stream.LoadFromFile strFileName '-- ContentType, Content-Length を設定 strDownloadFileName = Mid(strFileName, InStrRev(strFileName, "\")+ 1) Response.ContentType = "application/octet-stream" & vbCrLf & "Content-Disposition: attachment; filename=" & strDownloadFileName 'オブジェクト作成 Set objFSO = CreateObject("Scripting.FileSystemObject") fileSize = objFSO.GetFile(strFileName).Size offset = 0 bufferSize = 1000000 Do If fileSize <= offset Then Exit Do End If Stream.Position = offset data = Stream.Read(bufferSize) '-- バッファに出力 Response.BinaryWrite data offset = offset + bufferSize Loop ' Stream を閉じる Stream.Close Set Stream = Nothing 'Fileオブジェクトを開放 Set objFSO = Nothing End Sub [ メッセージ編集済み 編集者: kaz 編集日時 2008-09-17 09:37 ] |
1