web-dev-qa-db-ja.com

HTML5 File.sliceメソッドは実際に何をしていますか?

カスタムAPIを使用して、ユーザーが(できれば任意のサイズの)ファイルをアップロードできるようにしています。ファイルが大きすぎる場合は、チャンク化され、サーバーへの複数のリクエストで処理されます。

オンラインの多くの例に従って、FileおよびFileReader(HTML5)を使用するコードを書いています。一般に(オンラインで読んだものから)チャンクされたファイル転送では、人々は最初にファイルオブジェクトからデータのblobを取得します

_var file = $('input[type=file]')[0].files[0];
var blob = file.slice(start,end)
_

次に、FileReaderを使用してblobを読み取りますreadAsArrayBuffer(blob)またはreadAsBinaryString(blob)

そして最後にFileReader.onload(e)メソッドで、データをサーバーに送信します。ファイル内のすべてのチャンクに対してこのプロセスを繰り返します。

私の質問は

FileReaderを使用する必要があるのはなぜですか?私がそれを使用せず、_File.slice_でblobを送信するだけの場合、各リクエストでデータを送信しようとする前にスライス操作が実行されることが保証されます。 Fileオブジェクトは、作成時にファイル全体をロードしますか(そうではありませんか?)。 _File.slice_はパラメータで規定された位置にシークし、情報を読み取りますか?ドキュメントは、それがどのように実装されているかについての手掛かりを私に与えません。

28
Ponml

覚えておくべき重要なことは、FileはBlobから継承するということです。Fileには実際にはスライスメソッドがなく、Blobからこのメソッドを取得します。ファイルはいくつかのメタデータ属性を追加するだけです。

Blob(またはFile)を考える最良の方法は、データへのポインタとしてですが、実際のデータ自体ではありません。他の言語のファイルハンドルのようなものです。

UIスレッドのブロックを回避するために非同期に読み取るリーダーを使用しないと、Blobのデータに実際に到達することはできません。

Blob slice()メソッドは別のBlobを返すだけですが、これもデータではなく、元のBlob内のデータ範囲へのポインターであり、ビューへの境界付きポインターのようなものです。スライスされたBlobから実際にバイトを取り出すには、引き続きリーダーを使用する必要があります。スライスされたブロブの場合、リーダーは制限されます。

これは実際には、コード内で相対オフセットと絶対オフセットの束を持ち運ぶ必要がないように、便宜上意図されているだけであり、データの制限されたビューを取得して、バイトから読み取るかのようにリーダーを使用できます0。

XMLHttpRequestの場合(ブラウザーが新しいインターフェースをサポートしている場合)、データは送信時にストリーミングされ、BLOBの境界によって制約されます。基本的には、ストリームメソッドにファイルポインターを送信した場合に想像するのと同じように機能します(これは基本的には内部で行われていることです)。 https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data#Sending_binary_data

本質的に、それは怠惰なリーダーです。 blobが既にファイルシステムから読み込まれている、または読み込まれている場合、またはメモリ内に作成されている場合は、それを使用します。ただし、ファイルを使用している場合は、メインスレッドから非同期でロードされ、非同期にストリーミングされます。

ここでの基本的なロジックは、メインのスレッドをブロックする可能性があるため、ブラウザー開発者が読み取りを同期的に実行することを決して望んでいないということです。 Blob.slice()がどのように同期しているかに注意してください。これは、実際にIOを実行していないことを示しています。境界と(おそらく)ファイルポインターを設定しているだけです。

29
Clayton Gulick