web-dev-qa-db-fra.com

Implémenter une pause/reprise dans le téléchargement de fichier

J'essaie d'implémenter une pause/reprise dans mon gestionnaire de téléchargement, je fais des recherches sur le Web, je lis plusieurs articles et je modifie mon code en fonction de ceux-ci, mais CV semble ne pas fonctionner correctement. Des idées?

                if (!downloadPath.exists()) 
                    downloadPath.mkdirs(); 

                if (outputFileCache.exists())
                {
                    downloadedSize = outputFileCache.length();
                    connection.setAllowUserInteraction(true);
                    connection.setRequestProperty("Range", "bytes=" + downloadedSize + "-");
                    connection.setConnectTimeout(14000);
                    connection.connect();
                    input = new BufferedInputStream(connection.getInputStream());
                    output = new FileOutputStream(outputFileCache, true);
                    input.skip(downloadedSize); //Skip downloaded size
                }
                else
                {
                    connection.setConnectTimeout(14000);
                    connection.connect();
                    input = new BufferedInputStream(url.openStream());
                    output = new FileOutputStream(outputFileCache);
                }

                fileLength = connection.getContentLength();                 


                byte data[] = new byte[1024];
                int count = 0;
                int __progress = 0;
                long total = downloadedSize;

                while ((count = input.read(data)) != -1 && !this.isInterrupted()) 
                {
                    total += count;
                    output.write(data, 0, count);
                    __progress = (int) (total * 100 / fileLength);

                }
                output.flush();
                output.close();
                input.close();
20
NullPointer

Ok problème résolu, voici mon code pour les autres utilisateurs qui veulent implémenter pause/resume

        if (outputFileCache.exists())
        {
            connection.setAllowUserInteraction(true);
            connection.setRequestProperty("Range", "bytes=" + outputFileCache.length() + "-");
        }

        connection.setConnectTimeout(14000);
        connection.setReadTimeout(20000);
        connection.connect();

        if (connection.getResponseCode() / 100 != 2)
            throw new Exception("Invalid response code!");
        else
        {
            String connectionField = connection.getHeaderField("content-range");

            if (connectionField != null)
            {
                String[] connectionRanges = connectionField.substring("bytes=".length()).split("-");
                downloadedSize = Long.valueOf(connectionRanges[0]);
            }

            if (connectionField == null && outputFileCache.exists())
                outputFileCache.delete();

            fileLength = connection.getContentLength() + downloadedSize;
            input = new BufferedInputStream(connection.getInputStream());
            output = new RandomAccessFile(outputFileCache, "rw");
            output.seek(downloadedSize);

            byte data[] = new byte[1024];
            int count = 0;
            int __progress = 0;

            while ((count = input.read(data, 0, 1024)) != -1 
                    && __progress != 100) 
            {
                downloadedSize += count;
                output.write(data, 0, count);
                __progress = (int) ((downloadedSize * 100) / fileLength);
            }

            output.close();
            input.close();
       }
19
NullPointer

Il est impossible de dire ce qui ne va pas sans quelques informations supplémentaires, mais notez les points suivants:

  1. Vous devez faire une requête HTTP/1.1 (c'est difficile à dire à partir de votre exemple de code)
  2. Le serveur doit supporter HTTP/1.1
  3. Le serveur vous indiquera ce qu’il prend en charge avec un en-tête Accept-Ranges dans la réponse.
  4. If-Range devrait être l'etag que le serveur vous a donné pour la ressource, pas la dernière fois modifiée

Vous devriez vérifier votre demande d'intervalle avec quelque chose de simple pour tester l'origine car elle prend en charge d'abord la demande d'intervalle (comme curl ou wget)

5
stringy05

Il se peut que votre serveur prenne trop de temps à répondre (plus que le délai imparti) ou il est également indéniable que tous les serveurs ne prennent pas en charge la pause - resume . via Http, https, ftp ou udp.

Pause "peut signifier simplement lire une partie du flux et l’écrire sur le disque. Lors de la reprise, vous devrez utiliser les en-têtes pour spécifier le contenu restant à télécharger .

vous pouvez essayer quelque chose comme:

 HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    if(ISSUE_DOWNLOAD_STATUS.intValue()==ECMConstant.ECM_DOWNLOADING){
         File file=new File(DESTINATION_PATH);
        if(file.exists()){
             downloaded = (int) file.length();
         connection.setRequestProperty("Range", "bytes="+(file.length())+"-");
    }
}else{
    connection.setRequestProperty("Range", "bytes=" + downloaded + "-");
}
connection.setDoInput(true);
connection.setDoOutput(true);
progressBar.setMax(connection.getContentLength());
 in = new BufferedInputStream(connection.getInputStream());
 fos=(downloaded==0)? new FileOutputStream(DESTINATION_PATH): new FileOutputStream(DESTINATION_PATH,true);
 bout = new BufferedOutputStream(fos, 1024);
byte[] data = new byte[1024];
int x = 0;
while ((x = in.read(data, 0, 1024)) >= 0) {
    bout.write(data, 0, x);
     downloaded += x;
     progressBar.setProgress(downloaded);
}

et s'il vous plaît essayez de synchroniser les choses.

2
Manan Sharma

Je commencerais le débogage à partir de cette ligne:

connection.setRequestProperty("Range", "bytes=" + downloadedSize + "-");

À partir du code source, il n'est pas possible de déterminer ce que downloadedSize est, il est difficile d'élaborer plus avant, mais le format devrait être bytes=from-to.

Quoi qu'il en soit, je vous suggère d'utiliser Apache HttpClient pour éviter les pièges courants. Ici est une question de quelqu'un qui utilise Apache HttpClient sur un sujet similaire et qui fournit un exemple de code.

1
mindas

Je pense que vous avez juste besoin de supprimer la ligne input.skip (downloadsSize). Définir l'en-tête HTTP pour la plage d'octets signifie que serveur ignorera envoyant ces octets.

Supposons que vous ayez un fichier de 20 octets comprenant "aaaaabbbbbccccddddd", et supposons que le transfert soit mis en pause après le téléchargement de 5 octets. Ensuite, l'en-tête Range fera en sorte que le serveur envoie "bbbbbcccccddddd". Vous devez lire all de ce contenu et l'ajouter au fichier - no skip (). Mais l'appel skip () dans votre code ignorera "bbbbb", laissant "cccccddddd" à télécharger. Si vous avez déjà téléchargé au moins 50% du fichier, alors skip () épuisera toutes les entrées et rien ne se passera.

En outre, toutes les choses dans le post de stringy05 s'appliquent. Vous devez vous assurer que le serveur prend en charge HTTP/1.1, que l'en-tête Range est pris en charge pour la ressource (le contenu généré de manière dynamique peut ne pas le prendre en charge) et que la ressource n'est pas modifiée à l'aide de etag et de la date de modification.

0
picomancer