好记性不如烂笔头啊,今天分享下我最近弄得一个文件下载的东东,虽然只是单一下载但是对初学者可能有借鉴意义吧,高手就忽略吧,也希望大家有想法提出来一起进步哈。(第一次写博文)
原理:由client端发起request请求,由server端读取本地文件,由response对象返回文件流。
服务器端代码:
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
ServletOutputStream op = null;
try {
response.setContentType("text/html;charset=GBK");
byte[] data = 读取文件获取字节数组;
if(data==null){
process("数据为空".getBytes(),op);
return;
}
response.addHeader("content-length", data.length+"");
response.setHeader("content-disposition", "attachment; filename="
+ new String(fileName.getBytes("GBK"), "ISO8859_1"));
if (request.getSession().getServletContext().getMimeType(fileName) == null)
response.setContentType("Application/octet-stream;charset=GBK");
else
response.setContentType(request.getSession()
.getServletContext().getMimeType(fileName));
op = response.getOutputStream();
op.write(data, 0, data.length);
op.flush();
op.close();
} catch (Exception e) {
e.printStackTrace();
process((e.getMessage() == null ? "空指针" : e.getMessage()).getBytes(), op);
}
}
private void process(byte[] data, ServletOutputStream op) {
try {
op.write(data, 0, data.length);
op.flush();
op.close();
} catch (IOException e) {
e.printStackTrace();
}
}
读取文件的代码以及下载文件所必要的逻辑检查等我就忽略了,根据需求不同各自实现。
注意:
op=response.getOutputStream()此行代码一定要在response的header细心都设定之后再获取,因为代码顺序的原因会找出一些header信息的乱码比如文件名,所以大家要注意,好多人都遇到这个问题,包括ME。
下面是client端代码,我在客户端下载的时候,是再开一个线程。
@Override
protected void onActivityResult(int requestCode, int resultCode, final Intent data) {
switch (resultCode) {
case RESULT_OK:
final Handler m_Handler = new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.what == 0){
ComponentActivity.this.fileDownLoaderDialog.setMax(msg.getData().getInt("maxsize"));
}else if(msg.what == 1){
ComponentActivity.this.fileDownLoaderDialog.setProgress(msg.getData().getInt("downloader"));
}else if(msg.what == 2){
ComponentActivity.this.fileDownLoaderDialog.dismiss();
final String filePath = msg.getData().getString("filepath");
new AlertDialog.Builder(ComponentActivity.this)
.setTitle("下载提示:")
.setMessage(msg.getData().getString("message"))
.setPositiveButton("打开", new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which){
Intent intent = AndroidFileUtil.openFile(filePath);
try {
ComponentActivity.this.startActivity(intent);
} catch (Exception e) {
intent = AndroidFileUtil.getAllIntent(filePath);
ComponentActivity.this.startActivity(intent);
}
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which){
dialog.dismiss();
}
})
.show();
}else if(msg.what == 3){
new AlertDialog.Builder(ComponentActivity.this)
.setTitle("下载提示:")
.setMessage("文件已经存在是否要覆盖?")
.setPositiveButton("确定", new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which){
downLoad.start();
dialog.dismiss();
}
})
.setNegativeButton("取消下载", new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which){
if(thread != null && !thread.isInterrupted()){
httpconn.disconnect();
thread.interrupt();
}
dialog.dismiss();
}
})
.show();
}else if(msg.what == 4){
ComponentActivity.this.showDialog(1);
}else if(msg.what == -1){
ComponentActivity.this.fileDownLoaderDialog.dismiss();
new AlertDialog.Builder(ComponentActivity.this)
.setTitle("下载提示:")
.setMessage(msg.getData().getString("message"))
.setNegativeButton("确定", new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which){
dialog.dismiss();
}
})
.show();
}
super.handleMessage(msg);
}
};
downLoad = new Thread(new Runnable(){
@Override
public void run() {
try {
Thread.sleep(100);
Message message;
Bundle bund;
//*****************提示下载框*********************
message = new Message();
bund = new Bundle();
message.what = 4;
message.setData(bund);
m_Handler.sendMessageDelayed(message,0);
//**************************************
Bundle bundle = data.getExtras();
String savepath = bundle.getString("savePath");
InputStream dis = httpconn.getInputStream();
String fileName = httpconn.getHeaderField("content-disposition");
fileName = new String(fileName.getBytes("iso8859-1"),"gbk");
File newFile = new File(savepath + File.separator + fileName.split("=")[1]);
//*****************设置进度最大值*********************
message = new Message();
bund = new Bundle();
bund.putInt("maxsize", httpconn.getContentLength());
message.what = 0;
message.setData(bund);
m_Handler.sendMessageDelayed(message,0);
//**************************************
FileOutputStream fos = new FileOutputStream(newFile);
byte[] buffer = new byte[1024];
int len;
int downloader = 0;
try {
while ((len = dis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
downloader += len;
//*****************更新UI主线程显示当前累计下载量*********************
message = new Message();
bund = new Bundle();
bund.putInt("downloader", downloader);
message.what = 1;
message.setData(bund);
m_Handler.sendMessageDelayed(message,0);
//**************************************
}
fos.flush();
fos.close();
//*****************更新UI主线程提示文件下载完成*********************
message = new Message();
bund = new Bundle();
message.what = 2;
bund.putString("filepath", newFile.getAbsolutePath());
bund.putString("message", "文件下载成功!");
message.setData(bund);
m_Handler.sendMessageDelayed(message,0);
//**************************************
} catch (Exception e) {
Log.e("downloader error", e.getMessage());
}finally{
dis.close();
httpconn.disconnect();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (MalformedURLException e) {
Log.e("error", e.getMessage());
//**************************************
Message message = new Message();
Bundle bund = new Bundle();
message.what = -1;
bund.putString("message", "文件下载路径不正确,下载失败!");
message.setData(bund);
m_Handler.sendMessageDelayed(message,0);
//**************************************
} catch (IOException e) {
Log.e("error", e.getMessage());
//**************************************
Message message = new Message();
Bundle bund = new Bundle();
message.what = -1;
bund.putString("message", "读取文件流异常,下载失败!");
message.setData(bund);
m_Handler.sendMessageDelayed(message,0);
//**************************************
}
}
});
thread = new Thread(new Runnable(){
@Override
public void run() {
try {
Thread.sleep(100);
Message message;
Bundle bund;
Bundle bundle = data.getExtras();
String savepath = bundle.getString("savePath");
String url = bundle.getString("url");
httpconn = (HttpURLConnection) new URL(url).openConnection();
httpconn.setRequestMethod("GET");
httpconn.setDoInput(true);
httpconn.setDoOutput(true);
httpconn.setUseCaches(false);
httpconn.setInstanceFollowRedirects(true);
httpconn.connect();
String fileName = httpconn.getHeaderField("content-disposition");
fileName = new String(fileName.getBytes("iso8859-1"),"gbk");
Log.w("File Name is...", fileName);
File newFile = new File(savepath + File.separator + fileName.split("=")[1]);
if(newFile.exists()){
//*****************更新主线程UI提示文件覆盖选择*********************
message = new Message();
bund = new Bundle();
message.what = 3;
message.setData(bund);
m_Handler.sendMessageDelayed(message,0);
}else{
newFile.createNewFile();
downLoad.start();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (MalformedURLException e) {
Log.e("error", e.getMessage());
//**************************************
Message message = new Message();
Bundle bund = new Bundle();
message.what = -1;
bund.putString("message", "文件下载路径不正确,下载失败!");
message.setData(bund);
m_Handler.sendMessageDelayed(message,0);
//**************************************
} catch (IOException e) {
Log.e("error", e.getMessage());
//**************************************
Message message = new Message();
Bundle bund = new Bundle();
message.what = -1;
bund.putString("message", "读取文件流异常,下载失败!");
message.setData(bund);
m_Handler.sendMessageDelayed(message,0);
//**************************************
}
}
});
thread.start();
break;
default:
break;
}
}
因为在下载的时候要让用户来选择文件的保存目录,所以在用户要进行下载时首先是提示用户选择保存目录的,要打开FileBrowserActivity.java(后续文章呈现),所以就在
onActivityResult方法中实现了文件下载,这个因具体功能要求而异。
解释:在此处为何要用2个Thread来进行文件下载,实际上是我技术太差吧,呵呵。因为在httpconnect连接了之后我要获取fileName,检查文件在用户所选的目录是不是已经存在,第一个线程只是连接httpconnect获取文件名进行检查,如若用户选择覆盖下载,则执行读取inputstream,然后写入文件中。在此处用了
iso8859-1编码是因为我们的服务端也是同样的编码(也是为了兼容IOS),这个必须要统一。
具体代码就这么多,有好的想法提出来,一起进步我也是菜鸟一枚。