FileReaderを使用してファイルをダウンロードする

なぜ別の自転車を作ったのですか?




現在のプロジェクトの1つに取り組み、便利で高速なファイルダウンロードを実装する必要に再び直面しました。 Pluploadはおなじみのジェスチャーで発見しましたが、彼は考えました。



FileAPIについてはかなり前に聞いたことがありますが、当時はブラウザのサポートに問題があり、その結果、いずれにしても、代替ローダーを提供する必要があり、ゲーム全体としては価値がありませんでした。 しかし、現時点ではサイトのバックエンドのローダーであったため、サポートされているブラウザの数を絞り込むことが可能であり、私はこの問題をもう少し詳しく調べることにしました。







Habrには、2つの有益な記事が見つかりました。HTML5 へのファイルのアップロード機能と 、プリファレンスとダンサーを含むhtml5 File APIを使用 したファイルのアップロード機能です 。 2番目の記事は比較的古く、著者自身によると、そこに記載されているコードは「プロジェクトとその機能に結び付けられている」ため、長い仕上げが必要です。 最初の記事では、既製のコードを使用した特定のデモはありませんが、考えさせるための多くの情報と、掘り出すおおよその方向性を教えてくれました。



FileReaderを使用してダウンロード方法を選択しました。 現時点では、人気のあるブラウザのすべての新しいバージョンでサポートされています( 詳細 )。 ちなみに、すぐ近くにあるWindows 8の一部としてInternet Explorer 10を含めます(10月26日、小売販売の始まり)。



デモはどこにありますか?




デモはここで表示する、アーカイブをダウンロードできます



デモで何ができますか?




デモでは、一度に最大10個のファイルをダウンロードできます。各ファイルは5 MB以下、合計で50 MB以下です。 さらに、この制限は、ファイルの各バッチをロードした後にリセットされます。 ロード時に進行状況バーを表示します。 リストに操作可能なファイルがある限り、ボタンのオン/オフを切り替えます(アップロード/削除)。



デモには最小限の「プロジェクト固有の」コードが含まれており、任意のプロジェクトに簡単かつ迅速に実装できます。



そして、それはどのように機能しますか?




動作原理は、原則として、公然の秘密ではありません。



1)ところで、 デスクトップブラウザのすべての新しいバージョンで動作するドラッグアンドドロップの場合、次のようなイベントでハングアップします。



$('.dropbox') .on('drop', function(event) { if (event.originalEvent.dataTransfer.files.length) { //        addFiles. event.preventDefault(); event.stopPropagation(); addFiles(event.originalEvent.dataTransfer.files); $(this).css('border-color', 'gray'); $(this).css('color', 'gray'); } }) .on('dragenter', function(event) { //     . $(this).css('border-color', 'green'); $(this).css('color', 'green'); }) .on('dragleave', function(event) { //  . $(this).css('border-color', 'gray'); $(this).css('color', 'gray'); });
      
      







2)複数の属性を追加することにより、標準入力[type = file]からファイルを追加する機能を残します。これにより、一度に複数のファイルを選択できます。 ブラウザによるサポートについて考える必要さえありません(古いブラウザでは使用されそうにないバックエンドについて話していることを思い出してください)。



 <input type="file" name="file" size="1" multiple />
      
      







 $('input[type=file]').on('change', function(event) { addFiles(this.files); });
      
      







3)実際には、上記のリストで言及したaddFiles関数自体。 ここでは、重要ではないものを省略して、部分的に説明します。アーカイブ(/js/FRUploader.js)のスクリプトで完全に確認できます。 この関数は最後の手段ではなく、選択したファイルのリストにファイルを追加するだけで、さまざまな制限についてファイルを同時にチェックします(最大ファイルサイズの構成、合計ファイルサイズとファイル数の制限を提供します)。



 function addFiles(files) { $.each(files, function(i, v) { //     . if (v.size > maxfs) { maxfsFiles.push(v.name); } else if (flist.length >= maxfc) { $('div#maxfcerr').show('fast'); return false; } else if (maxts - curts < v.size) { $('div#maxtserr').show('fast'); return false; } else { //  . var fr = new FileReader(); fr.file = v; fr.readAsDataURL(v); //        . var row = document.createElement('tr'); /* *         ,       . */ $('table tbody').append(row); //     . flist.push({file: v, trnum: 'id' + index}); } }); }
      
      







4)ファイルをサーバーに直接アップロードする機能。 [ダウンロード]ボタンをクリックすると呼び出されます。



 function uploadFile(file, trnum) { if (file) { var xhr = new XMLHttpRequest(); upload = xhr.upload; //    progress,   "" -. upload.addEventListener('progress', function(event) { if (event.lengthComputable) { var pbar = $('tr.' + trnum + ' td.size div.pbar'); pbar.css('width', Math.round((event.loaded / event.total) * 100) + 'px'); } }, false); //    load,      - . upload.addEventListener('load', function(event) { var pbar = $('tr.' + trnum + ' td.size div.pbar'); pbar.css('width', '100px'); pbar.css('background', 'green'); }, false); //    error,     - . upload.addEventListener('error', function(event) { var pbar = $('tr.' + trnum + ' td.size div.pbar'); pbar.css('width', '100px'); pbar.css('background', 'red'); }, false); //  . xhr.open('POST', 'handler.php'); //  . xhr.setRequestHeader('Cache-Control', 'no-cache'); xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); xhr.setRequestHeader("X-File-Name", file.name); //  . xhr.send(file); } }
      
      







5)さて、そしてもちろん、サーバーハンドラー(handler.php)。 私のコードを基礎として取りたい人には、JavaScriptファイルのチェックだけに頼るべきではないことを思い出させてください。 サーバーでは、ファイルがすべての制限を通過するかどうかも確認する必要があります。 デモでは、これは省略されています。



 if (!array_key_exists('HTTP_X_FILE_NAME', $_SERVER) || !array_key_exists('CONTENT_LENGTH', $_SERVER)) exit(); $fname = $_SERVER['HTTP_X_FILE_NAME']; $fsize = $_SERVER['CONTENT_LENGTH']; if (!$fsize) exit(); file_put_contents("upload/".$fname, file_get_contents("php://input"));
      
      







ご覧のとおり、FileReaderを使用してダウンロードする場合、FormDataとは異なり、stdinから直接ファイルを読み書きできます( php:// input )。



プレビューが欲しい!




FileAPIを介したファイルダウンロードの実装のさまざまな例を考えると、画像をロードする前にプレビューを作成することにしばしば遭遇しました。 技術的には、これは簡単です。



 if (file.type.search(/image\/.*/) != -1) { var thumb = new Image(); thumb.src = ev.target.result; thumb.addEventListener("load", function() { maxwidth = 120; maxheight = 90; if (thumb.width > thumb.height) { thumb.height = thumb.height / (thumb.width / maxwidth); thumb.width = maxwidth; } else { thumb.width = thumb.width / (thumb.height / maxheight); thumb.height = maxwidth; } }, false); thumb.load; td.appendChild(thumb); delete thumb; }
      
      







しかし、非常に重い写真(10 MBから16 MBまでの8枚の写真)をアップロードしようとすると、すべてのブラウザーがバラバラになりました。ただし、Opera 12.02は例外でした。



これは、プレビュー画像がdata:/およびbase64でエンコードされたファイルコンテンツを介してロードされるためです。 120x90プレビューのため、16メガバイトの5184x3456画像がページに含まれています。 非常に長い間、結果の画像のサイズを変更してプレビューに使用するために、少なくともその場で何らかの方法を見つけようとしましたが、JavaScriptがこれを行う方法を知らないか、検索できません。 コメントの誰かが問題を解決する方法を提案した場合-私は非常に感謝します。



All Articles