Вопрос

Я чрезвычайно новичок в Java, и в основном я просто учил себя на ходу, поэтому я начал создавать апплет. Я хотел бы создать файл, который может выбрать файл с локального диска и загрузить его как POST-запрос multipart / form-data, но с индикатором выполнения . Очевидно, что пользователь должен предоставить разрешение апплету Java для доступа к жесткому диску. Теперь у меня уже работает первая часть: пользователь может выбрать файл, используя объект JFileChooser , который удобно возвращает объект File . Но мне интересно, что будет дальше. Я знаю, что File.length () даст мне полный размер файла в байтах, но как я могу отправить выбранный File в Интернет и как мне это сделать? контролировать, сколько байтов было отправлено? Заранее спасибо.

Это было полезно?

Решение 3

Я наткнулся на апплет Java-загрузчика с открытым исходным кодом и нашел все, что мне нужно было знать в его коде. Вот ссылки на сообщение в блоге, описывающее его, а также источник:

Статья
Исходный код

Другие советы

Чтобы проверить прогресс с помощью HttpClient, оберните MultipartRequestEntity вокруг единицы, которая считает отправленные байты. Оболочка находится ниже:

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

Затем реализует ProgressListener, который обновляет индикатор выполнения.
Помните, что обновление индикатора выполнения не должно выполняться в потоке отправки событий.

Более простая функция countingEntity не будет зависеть от конкретного типа сущности, а будет расширять 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));
    }
}

Количество байтов, возвращаемых слушателем, отличается от исходного размера файла. Итак, вместо Transfer ++ я изменил его так, чтобы Transfer = len ; это длина фактического количества байтов, записываемых в выходной поток. И когда я вычисляю сложение всех переданных байтов, оно равно фактическому ContentLength , возвращаемому CountingMultiPartEntity.this.getContentLength ();

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

Эта статья может оказаться полезной. Подробно объясняется использование HttpClient и FileUpload, оба проекта Apache, чтобы делать то, что вы хотите. Он также включает примеры кода.

Имейте в виду, что индикатор выполнения может вводить в заблуждение, когда промежуточный компонент в сети (например, HTTP-прокси интернет-провайдера или обратный HTTP-прокси перед сервером) потребляет загрузку быстрее, чем сервер.

Как отмечается в статье, опубликованной Винсентом, вы можете использовать Apache Commons для этого.

Немного подрезал


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с стоит:

Это основано на ответе тулера (на момент написания статьи была ошибка). Я немного изменил его, так что вот моя версия ответа tuler и mmyers (кажется, я не могу отредактировать их ответ). Я хотел попытаться сделать это немного чище и быстрее. Помимо ошибки (которую я обсуждаю в комментариях к их ответу), большая проблема, которую я имею с их версией, заключается в том, что она создает новый CountingOutputStream при каждой записи. Это может стать очень дорогим с точки зрения памяти - тонны выделений и сборщиков мусора. Меньшая проблема заключается в использовании делегата, когда он может просто развернуть MultipartEntity . Не уверенный, почему они выбрали это, таким образом я сделал это способом, с которым я был более знаком. Если кто-нибудь знает плюсы / минусы двух подходов, это было бы здорово. Наконец, метод FilterOutputStream # write (byte [], int, int) просто вызывает запись FilterOutputStream # (byte) в цикле. документация FOS рекомендует переопределять подклассы это поведение и делает это более эффективным. Лучший способ сделать это здесь - позволить исходному OutputStream обрабатывать запрос на запись.

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

Просмотрите HTTP-клиент для загрузки файла в Интернет. Это должно быть в состоянии сделать это. Я не уверен, как получить индикатор выполнения, но это будет связано с запросами к этому API.

Apache common - очень хороший вариант. Apache common позволяет настраивать следующие вещи.

<Ол>
  • Настройте (файл xml) максимальный размер файла / размер загружаемого файла
  • Путь к месту назначения (где сохранить загруженный файл)
  • Установите темп. папка, чтобы поменять файл, чтобы загрузка файла была быстрой.
  • Из других ответов вы можете просто переопределить метод AbstractHttpEntity для потомков или реализации public void writeTo (OutputStream outstream) , который вы используете, если не хотите создавать класс .

    Пример использования экземпляра 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]
                }
            });
        }
    
    };
    
    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top