Télécharger plusieurs fichiers en une seule opération.

Je ne suis pas sûr que cela soit possible en utilisant les technologies web standard.

je veux que l'utilisateur soit capable de télécharger plusieurs fichiers en une seule action. C'est-à-dire, cochez les cases à côté des fichiers, puis obtenez tous les fichiers qui ont été cochés.

Est-il possible - si oui, quelle stratégie de base recommandez-vous. Je sais que je peux utiliser la technologie comets pour créer des événements côté serveur qui déclenchent une réponse HTTPS, mais j'espère qu'il y a un moyen plus simple.

82
demandé sur Ankur 2010-02-26 07:09:35

15 réponses

HTTP ne supporte pas plus d'un téléchargement de fichier à la fois.

il y a deux solutions:

  • ouvrir x nombre de fenêtres pour lancer les téléchargements de fichiers (ce qui serait fait avec JavaScript)
  • meilleure solution créer un script pour compresser les fichiers
43
répondu Jacob Relkin 2010-02-26 04:12:25

var links = [
  'https://s3.amazonaws.com/Minecraft.Download/launcher/Minecraft.exe',
  'https://s3.amazonaws.com/Minecraft.Download/launcher/Minecraft.dmg',
  'https://s3.amazonaws.com/Minecraft.Download/launcher/Minecraft.jar'
];

function downloadAll(urls) {
  var link = document.createElement('a');

  link.setAttribute('download', null);
  link.style.display = 'none';

  document.body.appendChild(link);

  for (var i = 0; i < urls.length; i++) {
    link.setAttribute('href', urls[i]);
    link.click();
  }

  document.body.removeChild(link);
}
<button onclick="downloadAll(window.links)">Test me!</button>
65
répondu Matěj Pokorný 2015-06-06 12:12:41

vous pouvez créer un ensemble temporaire d'iframes cachées, lancer le téléchargement par GET ou POST à l'intérieur d'eux, attendre que les téléchargements pour commencer et supprimer si:

<!DOCTYPE HTML>
<html>
<body>
  <button id="download">Download</button> 

  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
  <script type="text/javascript">

     $('#download').click(function() {
       download('http://nogin.info/cv.doc','http://nogin.info/cv.doc');
     });

     var download = function() {
       for(var i=0; i<arguments.length; i++) {
         var iframe = $('<iframe style="visibility: collapse;"></iframe>');
         $('body').append(iframe);
         var content = iframe[0].contentDocument;
         var form = '<form action="' + arguments[i] + '" method="GET"></form>';
         content.write(form);
         $('form', content).submit();
         setTimeout((function(iframe) {
           return function() { 
             iframe.remove(); 
           }
         })(iframe), 2000);
       }
     }      

  </script>
</body>
</html>

ou, sans jQuery:

 function download(...urls) {
    urls.forEach(url => {
      let iframe = document.createElement('iframe');
      iframe.style.visibility = 'collapse';
      document.body.append(iframe);

      iframe.contentDocument.write(
        `<form action="${url.replace(/\"/g, '"')}" method="GET"></form>`
      );
      iframe.contentDocument.forms[0].submit();

      setTimeout(() => iframe.remove(), 2000);
    });
  }
49
répondu Dmitry Nogin 2018-03-30 08:33:33

cette solution fonctionne sur tous les navigateurs et ne déclenche pas d'Avertissements. Plutôt que de créer un iframe , nous créons ici un lien pour chaque fichier. Cela empêche les messages d'avertissement de surgir.

pour manipuler la partie en boucle, nous utilisons setTimeout , qui est nécessaire pour qu'il fonctionne dans IE.

/**
 * Download a list of files.
 * @author speedplane
 */
function download_files(files) {
  function download_next(i) {
    if (i >= files.length) {
      return;
    }
    var a = document.createElement('a');
    a.href = files[i].download;
    a.target = '_parent';
    // Use a.download if available, it prevents plugins from opening.
    if ('download' in a) {
      a.download = files[i].filename;
    }
    // Add a to the doc for click to work.
    (document.body || document.documentElement).appendChild(a);
    if (a.click) {
      a.click(); // The click method is supported by most browsers.
    } else {
      $(a).click(); // Backup using jquery
    }
    // Delete the temporary link.
    a.parentNode.removeChild(a);
    // Download the next file with a small timeout. The timeout is necessary
    // for IE, which will otherwise only download the first file.
    setTimeout(function() {
      download_next(i + 1);
    }, 500);
  }
  // Initiate the first download.
  download_next(0);
}
<script>
  // Here's a live example that downloads three test text files:
  function do_dl() {
    download_files([
      { download: "http://www.nt.az/reg.txt", filename: "regs.txt" },
      { download: "https://www.w3.org/TR/PNG/iso_8859-1.txt", filename: "standards.txt" },
      { download: "http://qiime.org/_static/Examples/File_Formats/Example_Mapping_File.txt", filename: "example.txt" },
    ]);
  };
</script>
<button onclick="do_dl();">Test downloading 3 text files.</button>
27
répondu speedplane 2017-09-26 18:30:41

la façon la plus facile serait de servir les multiples fichiers empaquetés dans un fichier ZIP.

je suppose que vous pourriez lancer plusieurs téléchargements de fichiers en utilisant un tas d'iframes ou popups, mais du point de vue de l'utilisabilité, un fichier ZIP est encore mieux. Qui veut cliquer à travers dix dialogues "Enregistrer sous" que le navigateur va soulever?

5
répondu Thilo 2010-02-26 04:11:59

jQuery version de l'iframe répond:

function download(files) {
    $.each(files, function(key, value) {
        $('<iframe></iframe>')
            .hide()
            .attr('src', value)
            .appendTo($('body'))
            .load(function() {
                var that = this;
                setTimeout(function() {
                    $(that).remove();
                }, 100);
            });
    });
}
3
répondu Yirmiyahu Fischer 2015-08-18 13:45:26
        <!doctype html>
    <html ng-app='app'>
        <head>
            <title>
            </title>
            <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
            <link rel="stylesheet" href="style.css">
        </head>
        <body ng-cloack>        
            <div class="container" ng-controller='FirstCtrl'>           
              <table class="table table-bordered table-downloads">
                <thead>
                  <tr>
                    <th>Select</th>
                    <th>File name</th>
                    <th>Downloads</th>
                  </tr>
                </thead>
                <tbody>
                  <tr ng-repeat = 'tableData in tableDatas'>
                    <td>
                        <div class="checkbox">
                          <input type="checkbox" name="{{tableData.name}}" id="{{tableData.name}}" value="{{tableData.name}}" ng-model= 'tableData.checked' ng-change="selected()">
                        </div>
                    </td>
                    <td>{{tableData.fileName}}</td>
                    <td>
                        <a target="_self" id="download-{{tableData.name}}" ng-href="{{tableData.filePath}}" class="btn btn-success pull-right downloadable" download>download</a>
                    </td>
                  </tr>              
                </tbody>
              </table>
                <a class="btn btn-success pull-right" ng-click='downloadAll()'>download selected</a>

                <p>{{selectedone}}</p>
            </div>
            <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
            <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
            <script src="script.js"></script>
        </body>
    </html>


app.js


var app = angular.module('app', []);            
app.controller('FirstCtrl', ['$scope','$http', '$filter', function($scope, $http, $filter){

$scope.tableDatas = [
    {name: 'value1', fileName:'file1', filePath: 'data/file1.txt', selected: true},
    {name: 'value2', fileName:'file2', filePath: 'data/file2.txt', selected: true},
    {name: 'value3', fileName:'file3', filePath: 'data/file3.txt', selected: false},
    {name: 'value4', fileName:'file4', filePath: 'data/file4.txt', selected: true},
    {name: 'value5', fileName:'file5', filePath: 'data/file5.txt', selected: true},
    {name: 'value6', fileName:'file6', filePath: 'data/file6.txt', selected: false},
  ];  
$scope.application = [];   

$scope.selected = function() {
    $scope.application = $filter('filter')($scope.tableDatas, {
      checked: true
    });
}

$scope.downloadAll = function(){
    $scope.selectedone = [];     
    angular.forEach($scope.application,function(val){
       $scope.selectedone.push(val.name);
       $scope.id = val.name;        
       angular.element('#'+val.name).closest('tr').find('.downloadable')[0].click();
    });
}         


}]);

exemple pratique: https://plnkr.co/edit/XynXRS7c742JPfCA3IpE?p=preview

3
répondu suresh 2016-05-03 08:46:51

je reconnais qu'un fichier zip est une meilleure solution... Mais si vous devez pousser plusieurs fichiers, voici la solution que j'ai trouvé. Il fonctionne dans IE 9 et plus (peut - être version inférieure aussi-je ne l'ai pas testé), Firefox, Safari et Chrome. Chrome affichera un message à l'utilisateur pour obtenir son accord pour télécharger plusieurs fichiers la première fois que votre site l'utilise.

function deleteIframe (iframe) {
    iframe.remove(); 
}
function createIFrame (fileURL) {
    var iframe = $('<iframe style="display:none"></iframe>');
    iframe[0].src= fileURL;
    $('body').append(iframe);
    timeout(deleteIframe, 60000, iframe);             
 }
 // This function allows to pass parameters to the function in a timeout that are 
 // frozen and that works in IE9
 function timeout(func, time) {
      var args = [];
      if (arguments.length >2) {
           args = Array.prototype.slice.call(arguments, 2);
      }
      return setTimeout(function(){ return func.apply(null, args); }, time);
 }
 // IE will process only the first one if we put no delay
 var wait = (isIE ? 1000 : 0);
 for (var i = 0; i < files.length; i++) {  
      timeout(createIFrame, wait*i, files[i]);
 }

Le seul effet secondaire de cette technique, est que l'utilisateur verra un délai entre le soumettre et la boîte de dialogue téléchargement de l'affichage. Pour minimiser cet effet, je vous suggère d'utiliser la technique de décrire ici et sur cette question détecter lorsque le navigateur reçoit téléchargement de fichier qui consiste à définir un cookie avec votre fichier pour savoir qu'il a commencé le téléchargement. Vous devrez vérifier ce cookie du côté client et l'envoyer du côté serveur. N'oubliez pas de définir le bon chemin pour votre cookie ou vous pourriez ne pas le voir. Vous devrez également adapter les solution pour le téléchargement de plusieurs fichiers.

2
répondu Melanie 2017-05-23 12:26:38

pour améliorer la réponse de @Dmitry Nogin: cela a fonctionné dans mon cas.

cependant, il n'est pas testé, car je ne suis pas sûr comment le dialogue de fichier fonctionne sur diverses combinaisons OS/navigateur. (Ainsi wiki communautaire.)

<script>
$('#download').click(function () {
    download(['http://www.arcelormittal.com/ostrava/doc/cv.doc', 
              'http://www.arcelormittal.com/ostrava/doc/cv.doc']);
});

var download = function (ar) {
    var prevfun=function(){};
    ar.forEach(function(address) {  
        var pp=prevfun;
        var fun=function() {
                var iframe = $('<iframe style="visibility: collapse;"></iframe>');
                $('body').append(iframe);
                var content = iframe[0].contentDocument;
                var form = '<form action="' + address + '" method="POST"></form>';
                content.write(form);
                $(form).submit();
                setTimeout(function() {    
                    $(document).one('mousemove', function() { //<--slightly hacky!
                        iframe.remove();
                        pp();
                    });
                },2000);
        }
        prevfun=fun; 
      });
      prevfun();   
}
</script>
1
répondu Karel Bílek 2014-03-06 00:03:43
           <p class="style1">



<a onclick="downloadAll(window.links)">Balance Sheet Year 2014-2015</a>

</p>

<script>
 var links = [
  'pdfs/IMG.pdf',
  'pdfs/IMG_0001.pdf',
 'pdfs/IMG_0002.pdf',
 'pdfs/IMG_0003.pdf',
'pdfs/IMG_0004.pdf',
'pdfs/IMG_0005.pdf',
 'pdfs/IMG_0006.pdf'

];

function downloadAll(urls) {
  var link = document.createElement('a');

  link.setAttribute('download','Balance Sheet Year 2014-2015');
  link.style.display = 'none';

  document.body.appendChild(link);

  for (var i = 0; i < urls.length; i++) {
    link.setAttribute('href', urls[i]);
    link.click();
  }

  document.body.removeChild(link);
}
</script>
0
répondu 2015-11-24 09:29:39

je suis à la recherche d'une solution pour faire cela, mais déballer les fichiers en javascript n'était pas aussi propre que je l'ai voulu. J'ai décidé d'encapsuler les fichiers dans un seul fichier SVG.

si vous avez les fichiers stockés sur le serveur (Je ne les ai pas), vous pouvez simplement définir href dans le SVG.

dans mon cas, je vais convertir les fichiers en base64 et les intégrer dans la SVG.

Edit: le SVG a très bien fonctionné. Si vous allez seulement télécharger le fichiers, ZIP pourrait être mieux. Si vous voulez afficher les fichiers, alors SVG semble supérieur.

0
répondu VectorVortec 2015-12-31 08:59:19

lors de l'utilisation de composants Ajax, il est possible de démarrer plusieurs téléchargements. Par conséquent, vous devez utiliser le https://cwiki.apache.org/confluence/display/WICKET/AJAX+mise à jour+et+fichier+téléchargement+dans+un+coup

ajoutez une instance D'AJAXDownload à votre Page ou autre. Créez un bouton AJAX et annulez onSubmit. Créer un AbstractAjaxTimerBehavior et commencer le téléchargement.

        button = new AjaxButton("button2") {

        private static final long serialVersionUID = 1L;

        @Override
        protected void onSubmit(AjaxRequestTarget target, Form<?> form)
        {
            MultiSitePage.this.info(this);
            target.add(form);

            form.add(new AbstractAjaxTimerBehavior(Duration.milliseconds(1)) {

                @Override
                protected void onTimer(AjaxRequestTarget target) {
                    download.initiate(target);
                }

            });     
        }

heureux téléchargement!

0
répondu stritzi 2016-11-23 16:10:01

Sous code 100% de travail.

Étape 1 : coller le code ci-dessous dans index.html fichier

<!DOCTYPE html>
<html ng-app="ang">

<head>
    <title>Angular Test</title>
    <meta charset="utf-8" />
</head>

<body>
    <div ng-controller="myController">
        <button ng-click="files()">Download All</button>
    </div>

    <script src="angular.min.js"></script>
    <script src="index.js"></script>
</body>

</html>

Step 2 : coller ci-dessous le code dans index.js fichier

"use strict";

var x = angular.module('ang', []);

    x.controller('myController', function ($scope, $http) {
        var arr = [
            {file:"http://localhost/angularProject/w3logo.jpg", fileName: "imageone"},
            {file:"http://localhost/angularProject/cv.doc", fileName: "imagetwo"},
            {file:"http://localhost/angularProject/91.png", fileName: "imagethree"}
        ];

        $scope.files = function() {
            angular.forEach(arr, function(val, key) {
                $http.get(val.file)
                .then(function onSuccess(response) {
                    console.log('res', response);
                    var link = document.createElement('a');
                    link.setAttribute('download', val.fileName);
                    link.setAttribute('href', val.file);
                    link.style.display = 'none';
                    document.body.appendChild(link);
                    link.click(); 
                    document.body.removeChild(link);
                })
                .catch(function onError(error) {
                    console.log('error', error);
                })
            })
        };
    });

NOTE : assurez-vous que les trois fichiers qui vont être téléchargés seront placés dans le même dossier avec angularProject/index.html ou angularProject/index.js "1519200920 de fichiers".

0
répondu solanki... 2017-08-19 08:48:01

cela fonctionne dans tous les navigateurs (IE11, firefox, Edge, Chrome et Chrome Mobile) Mes documents sont en plusieurs éléments select. Les navigateurs semblent avoir des problèmes lorsque vous essayez de le faire trop vite... J'ai donc utilisé un délai d'attente.

//user clicks a download button to download all selected documents
$('#downloadDocumentsButton').click(function () {
    var interval = 1000;
    //select elements have class name of "document"
    $('.document').each(function (index, element) {
        var doc = $(element).val();
        if (doc) {
            setTimeout(function () {
                window.location = doc;
            }, interval * (index + 1));
        }
    });
});

C'est une solution qui utilise des promesses:

 function downloadDocs(docs) {
        docs[0].then(function (result) {
            if (result.web) {
                window.open(result.doc);
            }
            else {
                window.location = result.doc;
            }
            if (docs.length > 1) {
                setTimeout(function () { return downloadDocs(docs.slice(1)); }, 2000);
            }
        });
    }

 $('#downloadDocumentsButton').click(function () {
        var files = [];
        $('.document').each(function (index, element) {
            var doc = $(element).val();
            var ext = doc.split('.')[doc.split('.').length - 1];

            if (doc && $.inArray(ext, docTypes) > -1) {
                files.unshift(Promise.resolve({ doc: doc, web: false }));
            }
            else if (doc && ($.inArray(ext, webTypes) > -1 || ext.includes('?'))) {
                files.push(Promise.resolve({ doc: doc, web: true }));
            }
        });

        downloadDocs(files);
    });
0
répondu Zach Painter 2018-07-18 20:58:01

obtenir la liste de l'url avec l'appel ajax et ensuite utiliser jQuery plugin pour télécharger plusieurs fichiers parallèles.

  $.ajax({
        type: "POST",
        url: URL,
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        data: data,
        async: true,
        cache: false,
        beforeSend: function () {
            blockUI("body");
        },
        complete: function () { unblockUI("body"); },
        success: function (data) {
           //here data --> contains list of urls with comma seperated
            var listUrls= data.DownloadFilePaths.split(',');
            listUrls.forEach(function (url) {
                $.fileDownload(url);
            });
            return false; 
        },
        error: function (result) {
            $('#mdlNoDataExist').modal('show');
        }

    });
0
répondu Ali 2018-08-08 14:32:29