JavaScript
jQuery

jsでファイルを一括ダウンロードしてみる

はじめに

ファイル1つ2つをダウンロードするときは、特に問題ないのですが、
数が増えてくると、なかなか面倒になってきます。
通常、こういうときには、サーバー側でファイルをzipなどで1つにまとめて、
ダウンロードすればいいのですが、
今回、日本語のファイル名が文字化けしてしまったため、jsで対応してみました。
(linuxでzipしたものが、windowsで文字化け/そろそろwindowsも問題なくなっているかも?)

当初、簡単に考えていたのですが、

  • jsでリンクを開いても最後のファイルしかダンロードされない。
  • 別タブで開いても動作しない。(そもそもかっこよくない)

などが発生し、ちょっと試行錯誤しましま。

html

ダウンロードのボタンを配置
ダウンロードの<a>タグに

  • ダウンロードのリンクにclassを付与
  • data-download-fileにファイル名を設定
<button id="download_button">一括ダウンロード</button><br>
<a class="download_file" data-download-file="テスト1.xlsx" href="/1/download">ダウンロード</a><br>
<a class="download_file" data-download-file="テスト2.xlsx" href="/2/download">ダウンロード</a><br>
<a class="download_file" data-download-file="テスト3.xlsx" href="/3/download">ダウンロード</a><br>
・
・
・

javascript

jsでは一旦サーバーからブラウザにデータを保持
その後、そのデータをPCに送るようにしています。

実際には、経過を表示する処理などを入れた方がいいです。

    $('#download_button').on('click', function(e){

        // 初期化処理
        var file_count = $(".download_file").length;  // ダウンロード数
        var try_count = 0;
        var err_file = [];

        $('.download_file').each(function() {

            var href = $(this).attr('href');
            var filename = $(this).data('download-file');

            loadFile(href, function (responce) {
         // 経過処理
                try_count++;
                if (responce!=null){
                    downloadAsFile(filename,responce);
                }else{
                    err_file.push(filename);
                }
                if (file_count==try_count){
                    // 終了処理
                    if (err_file.length!=0){
                        // エラー処理
                    }
                }
            });
        });
    });

    // サーバーからブラウザにロード
    var loadFile = function(href, cb) {
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){
            if (this.readyState == 4 ){
                if ( this.status == 200) {
                    cb(this.response);
                }else{
                    cb(null);
                }
            }
        }
        xhr.open('GET', href, true);
        xhr.responseType = 'blob';
        xhr.send(null);
    }

    // ブラウザからPCにダウンロード
    var downloadAsFile = function(filename, blob) {
        var objectURL = window.URL.createObjectURL(blob);
        var link = document.createElement("a");
        document.body.appendChild(link);
        link.href = objectURL;
        link.download = filename;
        link.click();
        document.body.removeChild(link);
    };

ファイル名をサーバーから送られたheaderから取得することは可能です。(やってないけど)

if ( this.status == 200) {
    var header = this.getResponseHeader('Content-Disposition');
    console.log(header);

このあと、headerをattachmentで切り取って、ゴニョゴニョすれば ( 参考まで )

注意事項

  • excelファイルのダウンロードを想定しています。
  • chrome以外で動作確認をしていません。
  • ファイルサイズが大きいときの動作確認をしていません。
  • ファイル数が多いときの動作確認をしていません。(50個ぐらいまでは確認しました)
  • サーバー側はエラーのときリダイレクトはしないでください。(リダイレクト先がダウンロードされます。)

参考リンク