Téléchargement de fichiers avec Java (avec barre de progression))

je suis extrêmement nouveau à Java, et ont pour la plupart été simplement l'enseignement de moi-même que je m'en vais, j'ai donc commencé la construction d'une applet. J'aimerais en faire un qui peut sélectionner un fichier à partir du disque local et le télécharger comme multipart/form-data POST request mais avec une barre de progression . Évidemment, l'utilisateur doit accorder la permission à L'applet Java pour accéder au disque dur. Maintenant j'ai déjà la première partie qui fonctionne: l'utilisateur peut sélectionner un fichier en utilisant un JFileChooser objet, qui retourne commodément un File objet. Mais je me demandais ce qui s'en vient. Je sais que File.length() va me donner la taille totale, en octets du fichier, mais comment puis-je envoyer la sélection File sur le web, et comment puis-je surveiller combien d'octets ont été envoyés? Merci à l'avance.

30
demandé sur SoaperGEM 2008-10-31 22:49:55

11 réponses

pour vérifier la progression en utilisant HttpClient, entourer la Multipartrequestity d'une entité qui compte les octets envoyés. L'emballage est ci-dessous:

import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.commons.httpclient.methods.RequestEntity;

public class CountingMultipartRequestEntity implements RequestEntity {
    private final RequestEntity delegate;

    private final ProgressListener listener;

    public CountingMultipartRequestEntity(final RequestEntity entity,
            final ProgressListener listener) {
        super();
        this.delegate = entity;
        this.listener = listener;
    }

    public long getContentLength() {
        return this.delegate.getContentLength();
    }

    public String getContentType() {
        return this.delegate.getContentType();
    }

    public boolean isRepeatable() {
        return this.delegate.isRepeatable();
    }

    public void writeRequest(final OutputStream out) throws IOException {
        this.delegate.writeRequest(new CountingOutputStream(out, this.listener));
    }

    public static interface ProgressListener {
        void transferred(long num);
    }

    public static class CountingOutputStream extends FilterOutputStream {

        private final ProgressListener listener;

        private long transferred;

        public CountingOutputStream(final OutputStream out,
                final ProgressListener listener) {
            super(out);
            this.listener = listener;
            this.transferred = 0;
        }

        public void write(byte[] b, int off, int len) throws IOException {
            out.write(b, off, len);
            this.transferred += len;
            this.listener.transferred(this.transferred);
        }

        public void write(int b) throws IOException {
            out.write(b);
            this.transferred++;
            this.listener.transferred(this.transferred);
        }
    }
}

implémente alors un ProgressListener qui met à jour une barre de progression.

Rappelez-vous que la mise à jour de la barre de progression ne doit pas s'exécuter sur le Thread Event Dispatch.

39
répondu tuler 2010-07-02 04:34:35

une entité comptable plus simple ne dépendrait pas d'un type d'entité spécifique, mais étendrait plutôt HttpEntityWrapped :

package gr.phaistos.android.util;

import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import org.apache.http.HttpEntity;
import org.apache.http.entity.HttpEntityWrapper;

public class CountingHttpEntity extends HttpEntityWrapper {

    public static interface ProgressListener {
        void transferred(long transferedBytes);
    }


    static class CountingOutputStream extends FilterOutputStream {

        private final ProgressListener listener;
        private long transferred;

        CountingOutputStream(final OutputStream out, final ProgressListener listener) {
            super(out);
            this.listener = listener;
            this.transferred = 0;
        }

        @Override
        public void write(final byte[] b, final int off, final int len) throws IOException {
            //// NO, double-counting, as super.write(byte[], int, int) delegates to write(int).
            //super.write(b, off, len);
            out.write(b, off, len);
            this.transferred += len;
            this.listener.transferred(this.transferred);
        }

        @Override
        public void write(final int b) throws IOException {
            out.write(b);
            this.transferred++;
            this.listener.transferred(this.transferred);
        }

    }


    private final ProgressListener listener;

    public CountingHttpEntity(final HttpEntity entity, final ProgressListener listener) {
        super(entity);
        this.listener = listener;
    }

    @Override
    public void writeTo(final OutputStream out) throws IOException {
        this.wrappedEntity.writeTo(out instanceof CountingOutputStream? out: new CountingOutputStream(out, this.listener));
    }
}
12
répondu ankostis 2011-09-06 11:25:30

j'ai fini par tomber sur une applet Java uploader open source et j'ai trouvé tout ce que je devais savoir dans son code. Voici les liens vers un billet de blog qui le décrit ainsi que la source:

Article

Code Source

6
répondu SoaperGEM 2009-07-18 21:46:23

le nombre d'octets retournés par l'auditeur est différent de la taille du fichier original. Ainsi, au lieu d'avoir transferred++ , je l'ai modifié de sorte que transferred=len ; c'est la longueur de la quantité réelle d'octets écrits dans le flux de sortie. Et quand je calcule l'addition des octets totaux transférés il est égal au ContentLength réel retourné par CountingMultiPartEntity.this.getContentLength();

public void write(byte[] b, int off, int len) throws IOException {
    wrappedOutputStream_.write(b,off,len);
    transferred=len;
    listener_.transferred(transferred);
}
5
répondu douggynix 2016-09-13 10:10:30

vous pourriez trouver ce article utile. Il explique en détail en utilisant HttpClient et FileUpload, les deux projets apache pour faire ce que vous voulez. Il comprend également des échantillons de code.

4
répondu Vincent Ramdhanie 2008-10-31 21:32:07

gardez à l'esprit que la barre de progression peut être trompeuse lorsqu'un composant intermédiaire du réseau (par exemple, un mandataire HTTP D'un FAI, ou un mandataire HTTP inverse devant le serveur) consomme votre téléchargement plus rapidement que le serveur.

4
répondu Alexander 2008-11-01 00:37:17

comme le note L'article Vincent, Vous pouvez utiliser Apache commons pour cela.

Peu ciselée


DiskFileUpload upload = new DiskFileUpload();
upload.setHeaderEncoding(ConsoleConstants.UTF8_ENCODING);

upload.setSizeMax(1000000);
upload.setSizeThreshold(1000000);

Iterator it = upload.parseRequest((HttpServletRequest) request).iterator();
FileItem item;
while(it.hasNext()){
    item = (FileItem) it.next();
    if (item.getFieldName("UPLOAD FIELD"){
       String fileName = item.getString(ConsoleConstants.UTF8_ENCODING);
       byte[] fileBytes = item.get();
    }
}

2
répondu el_eduardo 2008-10-31 21:57:54

Juste ma 2c en vaut la peine:

ceci est basé sur la réponse de tuler(a un bug au moment de l'écriture). Je l'ai légèrement modifié, donc voici ma version de la réponse de tuler et mmyers (Je ne semble pas pouvoir modifier leur réponse). Je voulais tenter de faire un peu plus propre et plus rapide. Outre le bug (dont je discute dans les commentaires sur leur réponse), le gros problème que j'ai avec leur version est qu'il crée un nouveau CountingOutputStream avec chaque écriture. Cela peut devenir très coûteux en termes de mémoire - des tonnes d'allocations et de la collecte des poubelles. Petit problème est qu'il utilise un délégué quand il pourrait se étendre le MultipartEntity . Je ne sais pas pourquoi ils ont choisi cela, alors je l'ai fait d'une manière que je connaissais mieux. Si quelqu'un sait avantages/inconvénients des deux approches, ce serait super. Enfin, la méthode FilterOutputStream#write(byte [], int, int) appelle simplement le FilterOutputStream#write(byte) dans une boucle. La FOS documentation recommande des sous-classes et rendre cela plus efficace. La meilleure façon de le faire ici est de laisser le flux de sortie sous-jacent gérer la demande d'écriture.

import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;

public class CountingMultiPartEntity extends MultipartEntity {

    private UploadProgressListener listener_;
    private CountingOutputStream outputStream_;
    private OutputStream lastOutputStream_;

    // the parameter is the same as the ProgressListener class in tuler's answer
    public CountingMultiPartEntity(UploadProgressListener listener) {
        super(HttpMultipartMode.BROWSER_COMPATIBLE);
        listener_ = listener;
    }

    @Override
    public void writeTo(OutputStream out) throws IOException {
        // If we have yet to create the CountingOutputStream, or the
        // OutputStream being passed in is different from the OutputStream used
        // to create the current CountingOutputStream
        if ((lastOutputStream_ == null) || (lastOutputStream_ != out)) {
            lastOutputStream_ = out;
            outputStream_ = new CountingOutputStream(out);
        }

        super.writeTo(outputStream_);
    }

    private class CountingOutputStream extends FilterOutputStream {

        private long transferred = 0;
            private OutputStream wrappedOutputStream_;

        public CountingOutputStream(final OutputStream out) {
            super(out);
                    wrappedOutputStream_ = out;
        }

        public void write(byte[] b, int off, int len) throws IOException {
                    wrappedOutputStream_.write(b,off,len);
                    ++transferred;
            listener_.transferred(transferred);
        }

        public void write(int b) throws IOException {
            super.write(b);
        }
    }
}
2
répondu Hamy 2010-07-02 03:31:39

regarder dans client HTTP pour télécharger le fichier vers le web. Il devrait être en mesure de le faire. Je ne sais pas comment obtenir la barre de progression, mais cela impliquerait de questionner cette API d'une façon ou d'une autre.

1
répondu Rontologist 2008-10-31 19:55:43

Apache common est une très bonne option. Apache common vous permet de configurer les choses suivantes.

  1. Configurer(fichier xml) la taille maximale du fichier/ télécharger le fichier "
  2. chemin de Destination (où sauvegarder le fichier téléchargé)
  3. fixe la température. dossier pour échanger le fichier , de sorte que l'upload de fichier rapide.
1
répondu Tony 2009-04-16 12:25:04

des autres réponses, vous pouvez simplement outrepasser la méthode AbstractHttpEntity ou implémentations public void writeTo(OutputStream outstream) que vous utilisez si vous ne voulez pas créer une classe.

exemple utilisant une instance FileEntity :

FileEntity fileEntity = new FileEntity(new File("img.jpg")){
    @Override
    public void writeTo(OutputStream outstream) throws IOException {
        super.writeTo(new BufferedOutputStream(outstream){
            int writedBytes = 0;

            @Override
            public synchronized void write(byte[] b, int off, int len) throws IOException {
                super.write(b, off, len);

                writedBytes+=len;
                System.out.println("wrote: "+writedBytes+"/"+getContentLength()); //Or anything you want [using other threads]
            }
        });
    }

};
1
répondu user3502626 2016-04-03 12:25:04