实现HttpClient上传文件进度条

我有下面的代码为一个文件上传与Apache的HTTP的客户端端(org.apache.http.client):
 public static void main(String[] args) throws Exception
 {
 String fileName = "test.avi";
 File file = new File(fileName);
 String serverResponse = null;
 HttpParams params = new BasicHttpParams();
 params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, true);
 HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
 HttpClient client = new DefaultHttpClient(params);
 HttpPut put = new HttpPut(" CodeGo.net  + fileName);
 FileEntity fileEntity = new FileEntity(file, "binary/octet-stream");
 put.setEntity(fileEntity); 
 HttpResponse response = client.execute(put);
 HttpEntity entity = response.getEntity();
 if (entity != null)
 {
  serverResponse = EntityUtils.toString(entity);
  System.out.println(serverResponse);
 }
 }
它工作的很好,但现在我想有一个进度条,显示文件上传进度。这怎么可能呢?我发现了一个代码片段的文件上传与Java(带进度条),但它是专为Apache的HTTP客户端端3(org.和RequestEntity类没有在Apache的HTTP客户端端4存在;。( 也许你有办法? 许多问候 班尼
本文地址 :CodeGo.net/341712/ 
------------------------------------------------------------------------------------------------------------------------- 
1.  我介绍一个派生 FileEntity 只是计数写入的字节。 OutputStreamProgress 做了实际的计数(一种decorator器的实际 OutputStream )。 这样做的好处(与装修一般)是,我不需要从文件流复制的实际就像实际的复制到输出流。我也可以改变一个不同的(新)之类的 NFileEntity 。 享受... FileEntity.java
public class FileEntity extends org.apache.http.entity.FileEntity {
 private OutputStreamProgress outstream;
 public FileEntity(File file, String contentType) {
  super(file, contentType);
 }
 @Override
 public void writeTo(OutputStream outstream) throws IOException {
  this.outstream = new OutputStreamProgress(outstream);
  super.writeTo(this.outstream);
 }
 /**
  * Progress: 0-100
  */
 public int getProgress() {
  if (outstream == null) {
   return 0;
  }
  long contentLength = getContentLength();
  if (contentLength <= 0) { // Prevent division by zero and negative values
   return 0;
  }
  long writtenLength = outstream.getWrittenLength();
  return (int) (100*writtenLength/contentLength);
 }
}
OutputStreamProgress.java
public class OutputStreamProgress extends OutputStream {
 private final OutputStream outstream;
 private volatile long bytesWritten=0;
 public OutputStreamProgress(OutputStream outstream) {
  this.outstream = outstream;
 }
 @Override
 public void write(int b) throws IOException {
  outstream.write(b);
  bytesWritten++;
 }
 @Override
 public void write(byte[] b) throws IOException {
  outstream.write(b);
  bytesWritten += b.length;
 }
 @Override
 public void write(byte[] b, int off, int len) throws IOException {
  outstream.write(b, off, len);
  bytesWritten += len;
 }
 @Override
 public void flush() throws IOException {
  outstream.flush();
 }
 @Override
 public void close() throws IOException {
  outstream.close();
 }
 public long getWrittenLength() {
  return bytesWritten;
 }
}

2.  这个答案通过添加一个简单的监听器OutputStreamProgress.java类,而不是由公众getProgress()方法(我真的不知道你是如何想调用getProgress()方法,因为该线程会执行内部延伸kilaka的回答的HttpClient的代码,整个你可能需要调用getProgress()!)。 请注意,您需要延长您希望每个实体类型的实体类,当你写你的HttpClient代码 CodeGo.net,你需要创建一个新的类型的实体。 我写了一个非常基本的写听者的WriteListener接口。在这里,您将添加你的逻辑做从OutputStreamProgress写报告,如更新一个进度条:) 非常感谢kilakadecorator理念在点票outstream潜行。 WriteLisener.java
public interface WriteListener {
 void registerWrite(long amountOfBytesWritten);
}
OutputStreamProgress.java
import java.io.IOException;
import java.io.OutputStream;
public class OutputStreamProgress extends OutputStream {
 private final OutputStream outstream;
 private long bytesWritten=0;
 private final WriteListener writeListener;
 public OutputStreamProgress(OutputStream outstream, WriteListener writeListener) {
  this.outstream = outstream;
  this.writeListener = writeListener;
 }
 @Override
 public void write(int b) throws IOException {
  outstream.write(b);
  bytesWritten++;
  writeListener.registerWrite(bytesWritten);
 }
 @Override
 public void write(byte[] b) throws IOException {
  outstream.write(b);
  bytesWritten += b.length;
  writeListener.registerWrite(bytesWritten);
 }
 @Override
 public void write(byte[] b, int off, int len) throws IOException {
  outstream.write(b, off, len);
  bytesWritten += len;
  writeListener.registerWrite(bytesWritten);
 }
 @Override
 public void flush() throws IOException {
  outstream.flush();
 }
 @Override
 public void close() throws IOException {
  outstream.close();
 }
}
BasicWriteListener
public class BasicWriteListener implements WriteListener {
public BasicWriteListener() {
 // TODO Auto-generated constructor stub
}
public void registerWrite(long amountOfBytesWritten) {
 System.out.println(amountOfBytesWritten);
}
}
MultipartEntityWithProgressBar
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
public class MultipartEntityWithProgressBar extends MultipartEntity {
 private OutputStreamProgress outstream;
 private WriteListener writeListener;
 @Override
 public void writeTo(OutputStream outstream) throws IOException {
  this.outstream = new OutputStreamProgress(outstream, writeListener);
  super.writeTo(this.outstream);
 }
 public MultipartEntityWithProgressBar(WriteListener writeListener)
 {
  super();
  this.writeListener = writeListener;
 }
 public MultipartEntityWithProgressBar(HttpMultipartMode mode, WriteListener writeListener)
 {
  super(mode);
  this.writeListener = writeListener;
 }
 public MultipartEntityWithProgressBar(HttpMultipartMode mode, String boundary, Charset charset, WriteListener writeListener)
 {
  super(mode, boundary, charset);
  this.writeListener = writeListener;
 }
 // Left in for clarity to show where I took from kilaka's answer
// /**
// * Progress: 0-100
// */
// public int getProgress() {
//  if (outstream == null) {
//   return 0;
//  }
//  long contentLength = getContentLength();
//  if (contentLength <= 0) { // Prevent division by zero and negative values
//   return 0;
//  }
//  long writtenLength = outstream.getWrittenLength();
//  return (int) (100*writtenLength/contentLength);
// }
}

3.  一个新的包组织结构。从公地-10(2.4)和它的类CountingOutputStream。 我改变了最初的代码,以反映我的项目需要一个多表单输入,(这个会费的征收服务器端)。 想想看,大文件的增量在我的测试中对应于4096个字节。该counterChanged()被调用传输的数据的每4096字节,什么是可以接受的情况。 看起来像:
public void post(String url, File sendFile) {
 HttpParams params = new BasicHttpParams();
 params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, true);
 HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
 HttpClient client = new DefaultHttpClient(params);
 HttpPost post = new HttpPost(url + "/" + sendFile.getName());
 MultipartEntity multiEntity = new MultipartEntity(); 
 MyFileBody fileBody = new MyFileBody(sendFile);
 fileBody.setListener(new IStreamListener(){
  @Override
  public void counterChanged(int delta) {
   // do something
   System.out.println(delta);
  }});
 multiEntity.addPart("file", fileBody);
 StringBody stringBody = new StringBody(sendFile.getName());
 multiEntity.addPart("fileName", stringBody);
 post.setEntity(multiEntity); 
 HttpResponse response = client.execute(post);
}
类MyFileBody
public class MyFileBody extends FileBody {
 private IStreamListener listener;
 public MyFileBody(File file) {
  super(file);
 }
 @Override
 public void writeTo(OutputStream out) throws IOException {
  CountingOutputStream output = new CountingOutputStream(out) {
   @Override
   protected void beforeWrite(int n) {
    if (listener != null && n != 0)
     listener.counterChanged(n);
    super.beforeWrite(n);
   }
  };
  super.writeTo(output);
 }
 public void setListener(IStreamListener listener) {
  this.listener = listener;
 }
 public IStreamListener getListener() {
  return listener;
 }
}
最后,监听器接口的样子:
public interface IStreamListener {
 void counterChanged(int delta);
}

4.  好家伙! 我解决了自己的问题,并做了一个简单的例子吧。 如果有任何问题,请随时提出。 在这里,我们走! ApplicationView.java
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.util.EntityUtils;
public class ApplicationView implements ActionListener
{
 File file = new File("C:/Temp/my-upload.avi");
 JProgressBar progressBar = null;
 public ApplicationView()
 {
 super();
 }
 public void createView()
 {
 JFrame frame = new JFrame("File Upload with progress bar - Example");
 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 frame.setBounds(0, 0, 300, 200);
 frame.setVisible(true);
 progressBar = new JProgressBar(0, 100);
 progressBar.setBounds(20, 20, 200, 30);
 progressBar.setStringPainted(true);
 progressBar.setVisible(true);
 JButton button = new JButton("upload");
 button.setBounds(progressBar.getX(),
   progressBar.getY() + progressBar.getHeight() + 20,
   100,
   40);
 button.addActionListener(this);
 JPanel panel = (JPanel) frame.getContentPane();
 panel.setLayout(null);
 panel.add(progressBar);
 panel.add(button);
 panel.setVisible(true);
 }
 public void actionPerformed(ActionEvent e)
 {
 try
 {
  sendFile(this.file, this.progressBar);
 }
 catch (Exception ex)
 {
  System.out.println(ex.getLocalizedMessage());
 }
 }
 private void sendFile(File file, JProgressBar progressBar) throws Exception
 {
 String serverResponse = null;
 HttpParams params = new BasicHttpParams();
 params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, true);
 HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
 HttpClient client = new DefaultHttpClient(params);
 HttpPut put = new HttpPut(" CodeGo.net  + file.getName());
 ProgressBarListener listener = new ProgressBarListener(progressBar);
 FileEntityWithProgressBar fileEntity = new FileEntityWithProgressBar(file, "binary/octet-stream", listener);
 put.setEntity(fileEntity);
 HttpResponse response = client.execute(put);
 HttpEntity entity = response.getEntity();
 if (entity != null)
 {
  serverResponse = EntityUtils.toString(entity);
  System.out.println(serverResponse);
 }
 }
}
FileEntityWithProgressBar.java
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.http.entity.AbstractHttpEntity;
/**
 * File entity which supports a progress bar.<br/>
 * Based on "org.apache.http.entity.FileEntity".
 * @author Benny Neugebauer ( CodeGo.net 
 */
public class FileEntityWithProgressBar extends AbstractHttpEntity implements Cloneable
{
 protected final File file;
 private final ProgressBarListener listener;
 private long transferredBytes;
 public FileEntityWithProgressBar(final File file, final String contentType, ProgressBarListener listener)
 {
 super();
 if (file == null)
 {
  throw new IllegalArgumentException("File may not be null");
 }
 this.file = file;
 this.listener = listener;
 this.transferredBytes = 0;
 setContentType(contentType);
 }
 public boolean isRepeatable()
 {
 return true;
 }
 public long getContentLength()
 {
 return this.file.length();
 }
 public InputStream getContent() throws IOException
 {
 return new FileInputStream(this.file);
 }
 public void writeTo(final OutputStream outstream) throws IOException
 {
 if (outstream == null)
 {
  throw new IllegalArgumentException("Output stream may not be null");
 }
 InputStream instream = new FileInputStream(this.file);
 try
 {
  byte[] tmp = new byte[4096];
  int l;
  while ((l = instream.read(tmp)) != -1)
  {
  outstream.write(tmp, 0, l);
  this.transferredBytes += l;
  this.listener.updateTransferred(this.transferredBytes);
  }
  outstream.flush();
 }
 finally
 {
  instream.close();
 }
 }
 public boolean isStreaming()
 {
 return false;
 }
 @Override
 public Object clone() throws CloneNotSupportedException
 {
 return super.clone();
 }
}
ProgressBarListener.java
import javax.swing.JProgressBar;
public class ProgressBarListener
{
 private int transferedMegaBytes = 0;
 private JProgressBar progressBar = null;
 public ProgressBarListener()
 {
 super();
 }
 public ProgressBarListener(JProgressBar progressBar)
 {
 this();
 this.progressBar = progressBar;
 }
 public void updateTransferred(long transferedBytes)
 {
 transferedMegaBytes = (int) (transferedBytes / 1048576);
 this.progressBar.setValue(transferedMegaBytes);
 this.progressBar.paint(progressBar.getGraphics());
 System.out.println("Transferred: " + transferedMegaBytes + " Megabytes.");
 }
}
快乐编码! 
5.  mmhh。无论工作在服务器总是返回IO错误:CRC校验失败=位于0x8! ->似乎破坏了流

本文标题 :如何获得一个文件的上传与Apache HttpClient的4进度条?
本文地址 :CodeGo.net/341712/ 

猜你喜欢

转载自blog.csdn.net/zacry/article/details/43230055