Android实现单一文件下载

好记性不如烂笔头啊,今天分享下我最近弄得一个文件下载的东东,虽然只是单一下载但是对初学者可能有借鉴意义吧,高手就忽略吧,也希望大家有想法提出来一起进步哈。(第一次写博文)


原理:由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),这个必须要统一。

具体代码就这么多,有好的想法提出来,一起进步我也是菜鸟一枚。
Android实现单一文件下载