通过HTTP表单通过MultipartEntityBuilder上传文件,并带有进度条

Phl*_*lip 45 android file-upload http

短版 - org.apache...MultipartEntity已被弃用,它的升级MultipartEntityBuilder,出现在我们的在线论坛代表性不足.我们来解决这个问题.如何注册回调,因此我的(Android)应用可以在上传文件时显示进度条?

长版 -这里的"失踪污垢简单的例子"的MultipartEntityBuilder:

public static void postFile(String fileName) throws Exception {
    // Based on: https://stackoverflow.com/questions/2017414/post-multipart-request-with-android-sdk

    HttpClient client = new DefaultHttpClient();
    HttpPost post = new HttpPost(SERVER + "uploadFile");
    MultipartEntityBuilder builder = MultipartEntityBuilder.create();        
    builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
    builder.addPart("file", new FileBody(new File(fileName)));
    builder.addTextBody("userName", userName);
    builder.addTextBody("password", password);
    builder.addTextBody("macAddress", macAddress);
    post.setEntity(builder.build());
    HttpResponse response = client.execute(post);
    HttpEntity entity = response.getEntity();

    // response.getStatusLine();  // CONSIDER  Detect server complaints

    entity.consumeContent();
    client.getConnectionManager().shutdown(); 

}  // FIXME  Hook up a progress bar!
Run Code Online (Sandbox Code Playgroud)

我们需要解决这个问题FIXME.(额外的好处是可中断上传.)但是(请纠正我是否我错了),所有在线示例似乎都不尽如人意.

例如,这个http://pastebin.com/M0uNZ6SB将文件上传为"二进制/八位字节流"; 不是"multipart/form-data".我需要真正的领域.

此示例使用Java文件上载(带进度条)显示如何覆盖*Entity*Stream.所以也许我可以告诉MultipartEntityBuilder.create()一个重写的实体米的上传进度?

因此,如果我想覆盖某些东西,并用一个每1000字节发送一个信号的计数流替换内置流,也许我可以扩展该FileBody部分,并覆盖它getInputStream和/或writeTo.

但是当我尝试时class ProgressiveFileBody extends FileBody {...},我得到了臭名昭着的java.lang.NoClassDefFoundError.

因此,当我围绕我的.jar文件进行探索,寻找缺失的Def时,有人可以检查我的数学,并且可能指出一个我忽略的更简单的修复方法吗?

Phl*_*lip 67

获奖代码(以壮观的Java-Heresy(tm)风格)是:

public static String postFile(String fileName, String userName, String password, String macAddress) throws Exception {

    HttpClient client = new DefaultHttpClient();
    HttpPost post = new HttpPost(SERVER + "uploadFile");
    MultipartEntityBuilder builder = MultipartEntityBuilder.create();        
    builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);

    final File file = new File(fileName);
    FileBody fb = new FileBody(file);

    builder.addPart("file", fb);  
    builder.addTextBody("userName", userName);
    builder.addTextBody("password", password);
    builder.addTextBody("macAddress",  macAddress);
    final HttpEntity yourEntity = builder.build();

    class ProgressiveEntity implements HttpEntity {
        @Override
        public void consumeContent() throws IOException {
            yourEntity.consumeContent();                
        }
        @Override
        public InputStream getContent() throws IOException,
                IllegalStateException {
            return yourEntity.getContent();
        }
        @Override
        public Header getContentEncoding() {             
            return yourEntity.getContentEncoding();
        }
        @Override
        public long getContentLength() {
            return yourEntity.getContentLength();
        }
        @Override
        public Header getContentType() {
            return yourEntity.getContentType();
        }
        @Override
        public boolean isChunked() {             
            return yourEntity.isChunked();
        }
        @Override
        public boolean isRepeatable() {
            return yourEntity.isRepeatable();
        }
        @Override
        public boolean isStreaming() {             
            return yourEntity.isStreaming();
        } // CONSIDER put a _real_ delegator into here!

        @Override
        public void writeTo(OutputStream outstream) throws IOException {

            class ProxyOutputStream extends FilterOutputStream {
                /**
                 * @author Stephen Colebourne
                 */

                public ProxyOutputStream(OutputStream proxy) {
                    super(proxy);    
                }
                public void write(int idx) throws IOException {
                    out.write(idx);
                }
                public void write(byte[] bts) throws IOException {
                    out.write(bts);
                }
                public void write(byte[] bts, int st, int end) throws IOException {
                    out.write(bts, st, end);
                }
                public void flush() throws IOException {
                    out.flush();
                }
                public void close() throws IOException {
                    out.close();
                }
            } // CONSIDER import this class (and risk more Jar File Hell)

            class ProgressiveOutputStream extends ProxyOutputStream {
                public ProgressiveOutputStream(OutputStream proxy) {
                    super(proxy);
                }
                public void write(byte[] bts, int st, int end) throws IOException {

                    // FIXME  Put your progress bar stuff here!

                    out.write(bts, st, end);
                }
            }

            yourEntity.writeTo(new ProgressiveOutputStream(outstream));
        }

    };
    ProgressiveEntity myEntity = new ProgressiveEntity();

    post.setEntity(myEntity);
    HttpResponse response = client.execute(post);        

    return getContent(response);

} 

public static String getContent(HttpResponse response) throws IOException {
    BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
    String body = "";
    String content = "";

    while ((body = rd.readLine()) != null) 
    {
        content += body + "\n";
    }
    return content.trim();
}

#  NOTE ADDED LATER: as this blasterpiece gets copied into various code lineages, 
#  The management reminds the peanut gallery that "Java-Heresy" crack was there
#  for a reason, and (as commented) most of that stuff can be farmed out to off-
#  the-shelf jar files and what-not. That's for the java lifers to tool up. This
#  pristine hack shall remain obviousized for education, and for use in a pinch.

#  What are the odds??
Run Code Online (Sandbox Code Playgroud)

  • 如果你有FileBody的问题,那么你包括旧的罐子.我刚刚从http://repo1.maven.org/maven2/org/apache/httpcomponents/下载了httpclient和httpcore的4.3版本,它就像一个魅力. (2认同)

小智 6

不能感谢Phlip足够的解决方案.以下是添加进度条支持的最终内容.我在AsyncTask中运行它 - 下面的进展使您可以将进度发布回AsyncTask中的方法,该方法为在AsyncTask中运行的类调用AsyncTask.publishProgress().进度条不是很平滑,但至少它会移动.在三星S4上传一个4MB图像文件后,它正在移动4K块.

     class ProgressiveOutputStream extends ProxyOutputStream {
            long totalSent;
            public ProgressiveOutputStream(OutputStream proxy) {
                   super(proxy);
                   totalSent = 0;
            }

            public void write(byte[] bts, int st, int end) throws IOException {

            // FIXME  Put your progress bar stuff here!
            // end is the amount being sent this time
            // st is always zero and end=bts.length()

                 totalSent += end;
                 progress.publish((int) ((totalSent / (float) totalSize) * 100));
                 out.write(bts, st, end);
            }
Run Code Online (Sandbox Code Playgroud)