Question

Je suis extrêmement novice en Java et la plupart du temps, tout en m'enseignant moi-même, j'ai donc commencé à créer une applet. J'aimerais en créer un qui puisse sélectionner un fichier sur le disque local et le télécharger en tant que demande POST multipart / form-data, mais avec une barre de progression . Il est évident que l'utilisateur doit autoriser l'applet Java à accéder au disque dur. Maintenant, la première partie fonctionne déjà: l'utilisateur peut sélectionner un fichier à l'aide d'un objet JFileChooser , qui renvoie commodément un objet Fichier . Mais je me demande ce qui vient ensuite. Je sais que File.length () me donnera la taille totale en octets du fichier, mais comment puis-je envoyer le Fichier sélectionné sur le Web et comment surveiller combien d'octets ont été envoyés? Merci d'avance.

Était-ce utile?

La solution 3

Je suis tombé sur une applet de programme de téléchargement Java à source ouverte et j'ai trouvé tout ce que je devais savoir dans son code. Voici des liens vers un article de blog le décrivant, ainsi que la source:

Article
Code source

Autres conseils

Pour vérifier la progression à l'aide de HttpClient, enroulez le MultipartRequestEntity autour de celui qui compte les octets envoyés. Le wrapper est en 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 ensuite un ProgressListener qui met à jour une barre de progression.
N'oubliez pas que la mise à jour de la barre de progression ne doit pas être exécutée sur le fil de discussion d'événement.

Une countingEntity 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));
    }
}

La quantité d'octets renvoyés par le programme d'écoute diffère de la taille du fichier d'origine. Donc, au lieu d’avoir transféré ++ , je l’ai modifié pour que soit transféré = len ; c'est la longueur de la quantité réelle d'octets en cours d'écriture dans le flux de sortie. Et lorsque je calcule l'addition du nombre total d'octets transférés, elle est égale à la valeur ContentLength renvoyée 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);
}

Vous trouverez peut-être cet article . Il explique en détail en utilisant HttpClient et FileUpload, les deux projets apache pour faire ce que vous voulez. Il comprend également des exemples de code.

N'oubliez pas que la barre de progression risque d'induire en erreur lorsqu'un composant intermédiaire du réseau (par exemple, le proxy HTTP d'un fournisseur de services Internet ou un proxy HTTP inverse devant le serveur) consomme votre téléchargement plus rapidement que le serveur.

Comme le note l'article publié par Vincent, vous pouvez utiliser Apache commons pour le faire.

Peu coupé


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();
    }
}

Juste ma valeur 2c:

Ceci est basé sur la réponse de tuler (a un bogue au moment de l'écriture). Je l'ai légèrement modifié, voici donc ma version de tuler et mmyers qui me répondent (je n'arrive pas à modifier leur réponse). Je voulais essayer de rendre cela un peu plus propre et plus rapide. Outre le bogue (dont je discute dans les commentaires sur leur réponse), le gros problème que je rencontre avec leur version est qu’il crée un nouveau CountingOutputStream à chaque écriture. Cela peut devenir très coûteux en termes de mémoire - des tonnes d'allocations et de collectes de déchets. Un problème moins important est qu'il utilise un délégué lorsqu'il peut simplement développer MultipartEntity . Je ne sais pas pourquoi ils ont choisi ça, alors je l'ai fait d'une manière que je connaissais mieux. Si quelqu'un connaît le pour / le contre des deux approches, ce serait formidable. Enfin, la méthode FilterOutputStream # write (byte [], int, int) appelle simplement FilterOutputStream # write (octet) dans une boucle. La la documentation FOS recommande l'utilisation de sous-classes redéfinies. ce comportement et le rendre plus efficace. Pour ce faire, la meilleure solution consiste à laisser le programme OutputStream 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);
        }
    }
}

Recherchez le client HTTP pour transférer le fichier sur le Web. Il devrait être capable de le faire. Je ne sais pas comment obtenir la barre de progression, mais cela impliquerait d'interroger cette API d'une manière ou d'une autre.

Apache common est une très bonne option. Apache common vous permet de configurer les éléments suivants.

  1. Configurez (fichier XML) la taille de fichier maximale / la taille du fichier de téléchargement
  2. Chemin de destination (où enregistrer le fichier téléchargé)
  3. Réglez le temp. dossier pour échanger le fichier, afin que le téléchargement du fichier soit rapide.

À partir des autres réponses, vous pouvez simplement remplacer la méthode AbstractHttpEntity ou les implémentations public void writeTo (OutputStream outstream) que vous utilisez si vous ne souhaitez pas créer de classe. .

Un 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]
            }
        });
    }

};
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top