出典:Baoyu BLOG
1. コンポーネントレスアップロードの原理を例を挙げて少しずつ説明していきます。 クライアントのHTMLは以下の通りです。アップロードされた添付ファイルを参照するには、<input type="file"> 要素を渡しますが、フォームの enctype 属性を必ず「multipart/form-data」に設定してください。
<form method="post" action="upload.asp" enctype="multipart/form-data">
<ラベル>
<input type="file" name="file1" />
</label>
<br />
<input type="text" name="ファイル名" value="デフォルトのファイル名"/>
<br />
<input type="submit" value="Submit"/>
<input type="reset" value="リセット"/>
</form>
バックグラウンド ASP プログラムでは、フォームから送信された ASCII データを非常に簡単に取得できました。ただし、アップロードされたファイルを取得する必要がある場合は、Request オブジェクトの BinaryRead メソッドを使用してファイルを読み取る必要があります。 BinaryRead メソッドは、現在の入力ストリームから指定されたバイト数のバイナリ読み取りを実行します。BinaryRead メソッドを使用すると、Request.Form または Request.QueryString コレクションは使用できなくなることに注意してください。 Request オブジェクトの TotalBytes プロパティと組み合わせると、フォームによって送信されたすべてのデータをバイナリに変換できますが、これらのデータはすべてエンコードされます。まず、これらのデータがどのようにエンコードされるかを見てみましょう。 コードをセグメント化して、BinaryRead によって読み取られたバイナリをバックグラウンドで Upload.asp に出力します。この例では大きなファイルをアップロードしないでください。アップロードすると、ブラウザがクラッシュする可能性があります)。
<%
Dim biData、PostData
サイズ = Request.TotalBytes
biData = Request.BinaryRead(サイズ)
PostData = BinaryToString(biData,Size)
Response.Write "<pre>" & PostData & "</pre>" 'preを使用し、そのままの形式で出力します
' RecordSet を使用してバイナリ ストリームをテキストに変換します
関数 BinaryToString(biData,Size)
Const adLongVarChar = 201
Set RS = CreateObject("ADODB.Recordset")
RS.Fields.Append "mBinary"、adLongVarChar、サイズ
RS.オープン
RS.AddNew
RS("mBinary").AppendChunk(biData)
RS.アップデート
BinaryToString = RS("mBinary").Value
RS.閉じる
終了機能
%>
簡単にするために、最も単純なテキスト ファイル (G:homepage.txt、内容が「Baoyu: http://www.webuc.net 」) をアップロードして、デフォルト値「default filename」のままにしておきます。テキスト ボックスのファイル名を送信して出力を確認します:
--------------------------------7d429871607fe
コンテンツの配置: フォームデータ名 = "ファイル1"; ファイル名 = "G:homepage.txt";
コンテンツタイプ: テキスト/プレーン
Baoyu: http://www.webuc.net
------------------------7d429871607fe
コンテンツの配置: フォームデータ名 = "ファイル名"
デフォルトのファイル名
------------------------7d429871607fe--
フォーム内の項目については、「-----」であることがわかります。 ------------------------7d429871607fe" このような境界線はピースを分割するために使用され、各ピースの先頭には何らかの説明情報が存在します。例: Content- Disposition: form-data; name="filename"、説明情報では、name="filename" によってフォーム項目の名前を知ることができます。 filename="G:homepage.txt" のようなコンテンツがある場合、それはアップロードされたファイルであることを意味します。アップロードされたファイルの場合、説明情報にはもう 1 行 Content-Type: text/plain が記述されます。ファイルのコンテンツタイプ。説明情報と本文情報は改行で区切られます。
このルールに従って、データを分割し、分割されたデータを処理する方法はほぼわかりました。ただし、1 つ見落としがちな問題、それが境界値 (上記の「------」) です。例) -----------------------7d429871607fe") はどうやって知りましたか?幸いなことに、この境界値は、ASP の Request.ServerVariables("HTTP_CONTENT_TYPE") を通じて取得できます。たとえば、上記の例では、HTTP_CONTENT_TYPE の内容は次のようになります。 border=-- ------------------------7d429871607fe" とすると、enctype="multipart/form-data" かどうかを判断できるだけでなく、 " (使用しない場合は以下を実行する必要はありません)、境界値の取得も可能ですboundary=---------------------- ----- 7d429871607fe。 (注: ここで取得した境界値は、上記の境界値よりも先頭の「-」が少ないです。追加した方がよいでしょう。)
データをどのように分析するかについては、詳細は説明しません。これは、InStr や Mid などの関数を使用して必要なデータを分離することに他なりません。
2. チャンクでアップロードする場合、進行状況の記録にはリアルタイムで進行状況バーが反映される必要があります。重要なのは、現在のサーバーがリアルタイムで取得したデータの量を知ることです。アップロードのプロセスを振り返ると、Request.BinaryRead(Request.TotalBytes) によって実装されていますが、リクエストのプロセス中に、現在のサーバーがどれだけのデータを取得したかを知ることはできません。したがって、取得したデータをいくつかの部分に分割し、アップロードされたブロックの数に基づいて、現在アップロードされているデータのサイズを計算できる場合のみ、回避策を使用できます。つまり、1K を 1 ブロックとすると、1MB をアップロードする入力ストリームを 1024 ブロックに分割して取得することになります。たとえば、100 ブロックを取得した場合は、100K がアップロードされたことになります。私がブロックすることを提案したとき、多くの人は、BinaryRead メソッドが指定されたサイズを読み取るだけでなく、連続して読み取ることもできることを無視していたため、それが信じられないと感じました。
先ほどの例に基づいて、ブロック読み取りの整合性を検証する例を作成します (この例では大きなファイルはアップロードされません。アップロードしない場合、ブラウザーがクラッシュする可能性があることに注意してください):
<%
Dim biData、PostData、TotalBytes、ChunkBytes
ChunkBytes = 1 * 1024 ' チャンク サイズは 1K
TotalBytes = Request.TotalBytes '合計サイズ
PostData = "" ' テキスト型に変換されたデータ
ReadedBytes = 0 '0に初期化されます
' 分割して読む
ReadedBytes < TotalBytes の間実行します
biData = Request.BinaryRead(ChunkBytes) '現在のチャンク
PostData = PostData & BinaryToString(biData,ChunkBytes) '現在のチャンクをテキストに変換して結合します
ReadedBytes = ReadedBytes + ChunkBytes 'レコード読み取りサイズ
ReadedBytes > TotalBytes の場合、ReadedBytes = TotalBytes
ループ
Response.Write "<pre>" & PostData & "</pre>" ' preを使用し、そのままの形式で出力します
' バイナリストリームをテキストに変換します
関数 BinaryToString(biData,Size)
Const adLongVarChar = 201
Set RS = CreateObject("ADODB.Recordset")
RS.Fields.Append "mBinary"、adLongVarChar、サイズ
RS.オープン
RS.AddNew
RS("mBinary").AppendChunk(biData)
RS.アップデート
BinaryToString = RS("mBinary").Value
RS.閉じる
終了機能
%>
先ほどテキスト ファイルをアップロードしてみます。出力結果は、ブロックで読み取られたコンテンツが完了したことを示しています。また、while ループで、ループするたびに現在のステータスをアプリケーションに記録し、Access を渡すことができます。アップロードの進行状況バーを動的に取得するアプリケーション。
また、上記の例では、文字列の結合が使用されています。バイナリ データを結合する場合は、ADODB.Stream オブジェクトの Write メソッドを使用できます。サンプル コードは次のとおりです。
Set bSourceData = createobject("ADODB.Stream") )
bSourceData.Open
bSourceData.Type = 1 'バイナリ
ReadedBytes < TotalBytes の間実行します
biData = Request.BinaryRead(ChunkBytes)
bSourceData.Write biData ' write メソッドを直接使用して、現在のファイル ストリームを bSourceData に書き込みます
ReadedBytes = ReadedBytes + ChunkBytes
ReadedBytes > TotalBytes の場合、ReadedBytes = TotalBytes
Application("ReadedBytes") = ReadedBytes
ループ
3. アップロードされたファイルを保存します。アップロードされたファイルを分離した後、データの種類によって保存方法が異なります。
バイナリ データの場合は、バイナリ ストリームを直接保存できます
。ADODB.Stream オブジェクトになります。
テキスト データの場合は、TextStream オブジェクトの Write メソッドを使用してテキスト データをファイルに保存できます。
小さなファイルをアップロードする場合、テキスト データとバイナリ データは簡単に相互に変換できます。ただし、ADODB.Stream オブジェクトの場合、ファイルとして保存する前にすべてのデータをロードする必要があるため、このメソッドを使用して大きなファイルをアップロードすると、大量のメモリが占有されます。 TextStream オブジェクトの場合は、ファイルの作成後にその一部を一度に書き込んだり、複数回書き込んだりできるため、データを取得する原理と組み合わせることで、サーバーのメモリ領域を占有しないという利点があります。上記で分析されたブロックを使用すると、アップロードされた各データをファイルの中央に書き込むことができます。以前、最初の方法を使用して 200 MB を超えるファイルをアップロードしたことがありますが、最終的には、コンピュータの仮想メモリが不足していることが直接わかりました。進行状況バーにはファイルがアップロードされたことが示されていますが、最終的にはファイルはまだ保存されていません。後者の方法を使用すると、アップロード処理中にメモリは基本的に変更されません。
4. 未解決の問題 Bestcomy のブログで、Asp.Net アップロード コンポーネントを Sever.SetTimeOut から独立させることができると説明していますが、Asp では、大きなファイルをアップロードするには Server.SetTimeOut しか使用できませんでした。非常に大きな値に設定する必要があります。もっと良い解決策があるかどうかはわかりません。
ファイルを保存するときに TextStream オブジェクトの Write メソッドを使用すると、アップロード時にユーザーがファイル転送を中断した場合でも、アップロードされたファイルの部分はそのまま残り、アップロードを再開できれば便利です。重要な問題は、Request.BinaryRead メソッドはブロック単位で読み取ることができますが、読み取りの特定のセクションをスキップできないことです。
5. 結論 基本的に原理はわかりやすく説明されていますが、実際のコードはこれよりもはるかに複雑であり、最も面倒な部分は、取得したデータごとに分析する必要があります。フォーム項目がまだアップロードされたファイルであるかどうか、およびファイルがアップロードされているかどうかを分析します。
上記の説明に基づいて、独自の強力なコンポーネントレスアップロードコンポーネントを開発することもできると思います。コードだけを気にしていて、自分でコードを書く方法を知らない人が増えているのではないかと思います。時間がないのかもしれません。レベルが十分ではないのかもしれません。そして、コードが習慣になっているだけかもしれません。 CSDN で見られるテクノロジーが多すぎます 8 部構成のエッセイ - 説明の段落、その後にすべてのコード。人に釣りを教えることは、私がコードを与えたとしても、次に同じような問題に遭遇したとき、その理由を考えずにただそれを使うかもしれません。この記事がより多くの人が何かを学ぶのに役立つことを願っています。最も重要なことは何かを「啓発」することです。