利用Http在Android客户端与Web服务器之间断点续传中大文件
一、还是先说一下需要用到的工具:
1.服务端:IDEA(真的超好用)、Tomcat
2.客户端:Android
二、上代码
服务端代码:
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.Socket;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;@WebServlet(name = "downloadServlet")
public class downloadServlet extends HttpServlet {// String sfilepath="G:/niki/upload/百年孤独.txt";String sfilepath="G:/niki/upload/pics.rar";String filename;String bytes_downloaded;private Socket socket;protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("客户端来啦!!!!!!!!"); //请各位读者忽略我这个调试的习惯用语……byte[] buffer=new byte[1024];InputStream inputStream=request.getInputStream();ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();int length;if ((length=inputStream.read(buffer))!=-1){byteArrayOutputStream.write(buffer,0,length);}String str=String.valueOf(byteArrayOutputStream);if(str.length()>3){String str_result=URLDecoder.decode(str.substring(1,str.length()-1),"UTF-8");String str_response="准备发送文件的服务器已经收到客户端的消息:\n";System.out.println(str_response+str_result);JSONObject jsonObject= JSONObject.fromObject(str_result);filename=jsonObject.getString("filename");bytes_downloaded=jsonObject.getString("bytes_downloaded");System.out.println("从客户端收到的消息为:\n文件名:《"+filename+"》\n已经下载的字节数为:"+bytes_downloaded);}String path="G:/niki/upload/";//构建上传路径response.setCharacterEncoding("utf-8");OutputStreamWriter osw = null;osw = new OutputStreamWriter(response.getOutputStream(), "UTF-8");PrintWriter pw = new PrintWriter(osw, true);Map<String ,String> map=new HashMap<>();map.put("filename", URLEncoder.encode(filename,"UTF-8"));System.out.println("客户端说已经下载了:"+bytes_downloaded+"个字节");File file=new File(sfilepath);if(file.isFile()&&file.exists()){System.out.println("此书存在");response.addHeader("bytes_counts", String.valueOf(file.length()));response.addHeader("filename","pics.rar");DataOutputStream dataOutputStream=new DataOutputStream(response.getOutputStream());RandomAccessFile randomAccessFile=new RandomAccessFile(sfilepath,"r");byte[] filebuffer=new byte[1024];randomAccessFile.skipBytes(Integer.parseInt(bytes_downloaded));int len= randomAccessFile.read(filebuffer);if (len!=-1){System.out.println("刚刚发送了"+len+"个字节");dataOutputStream.write(filebuffer,0,len);dataOutputStream.flush();}}else{}pw.flush();}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}
}
客户端:
1.DownLoadFileActivity
package com.example.administrator.filetransportapp.FileOperator;import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;import com.example.administrator.filetransportapp.R;
import com.example.administrator.filetransportapp.Utils.Utils;import net.sf.json.JSONArray;import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;/*** Created by Administrator on 2017/11/8.*/public class DownLoadFileActivity extends Activity {/*** 控件* */Button btdownload;ProgressBar mpBar;TextView tvPbar; //用来显示下载的进度TextView tvserverdata; //用来显示服务端返回的数据/**** 通信所需* */Handler handler=new Handler(new Handler.Callback() {@Overridepublic boolean handleMessage(Message msg) {//获取数据final String mess=msg.getData().getString("message").toString();final int bytes_sum=msg.getData().getInt("bytes_sum");final int bytes_downloaded=msg.getData().getInt("bytes_downloaded");//改变UI的显示runOnUiThread(new Runnable() {@Overridepublic void run() {tvserverdata.setText("下载中...");tvPbar.setText(bytes_downloaded+"/"+bytes_sum);mpBar.setMax(bytes_sum);mpBar.setProgress(bytes_downloaded);}});if(bytes_downloaded<bytes_sum){Runnable task=new Runnable() {@Overridepublic void run() {task_count++;downFileThread=new HttpDownLoadThread(handler,filename,DownLoadFileActivity.this,false);downFileThread.start();}};excutor.execute(task);}else{runOnUiThread(new Runnable() {@Overridepublic void run() {tvserverdata.setText("下载完成!");}});}return true;}});boolean flag=true;HttpDownLoadThread downFileThread;String filename="pics.rar";//String filename="百年孤独.txt";Executor excutor;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.downloadfileactivity);Init();excutor= Executors.newFixedThreadPool(40); //初始化一个固定数量为40的线程池}//测试多线程public void TestExcution(){}public void Init(){btdownload= (Button) findViewById(R.id.bt_download);mpBar=(ProgressBar)findViewById(R.id.progressbar);tvPbar=(TextView)findViewById(R.id.tv_progress);tvserverdata=(TextView)findViewById(R.id.server_data);}int task_count=0;public void DownLoadFile(View v){new Thread(new Runnable() {@Overridepublic void run() {downFileThread=new HttpDownLoadThread(handler,filename,DownLoadFileActivity.this,true);downFileThread.run();}}).start();}}
2.HttpDownLoadThread
package com.example.administrator.filetransportapp.FileOperator;import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;import com.example.administrator.filetransportapp.Utils.Utils;import net.sf.json.JSONArray;
import net.sf.json.JSONObject;import org.apache.http.protocol.ResponseDate;import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;/*** Created by Administrator on 2017/11/10.*/public class HttpDownLoadThread extends Thread {Context context;String filename="";int bytes_sum=0; //此次任务需要下载的总量int bytes_downloaded=0; //此次任务已经下载的字节数int MAX=1024; //此次任务每次最多接收的数据量大小byte[] buffer=new byte[MAX];boolean flag=false; //标志此次任务是否成功打开通信链路StringBuffer stringBuffer=new StringBuffer();/**** 用于此线程与主线程进行通信* */Handler handler;Bundle b;//文件路径+文件名 [此处最好是把文件格式给带上]int count=0;File dir;String externalstorsgepath="";public HttpDownLoadThread(Handler handler,String Filename,Context context,boolean flag){this.handler=handler;this.filename=Filename;this.context=context;externalstorsgepath= getSdCardPath();dir=new File(externalstorsgepath+"/nikidata");if(dir.exists()){//dir.mkdirs();System.out.println("目录已经存在");File file=new File(dir.getAbsolutePath(),filename);if(file.exists()){if(flag){file.delete();System.out.println("已经删除了"+file.getAbsolutePath());try {file.createNewFile();System.out.println("以及成功创建"+file.getAbsolutePath());} catch (IOException e) {e.printStackTrace();}}}else{try {file.createNewFile();} catch (IOException e) {e.printStackTrace();}System.out.println("以及成功创建"+file.getAbsolutePath());}}}@Overridepublic void run() {//构建URL的格式为: http://IP地址:监听的端口号/Servlet的路径final String strUrl = "http://"+ Utils.IP+":8080/downloadServlet";final URL[] url = {null};//第一步:访问网站,进行连接try {url[0] =new URL(strUrl);HttpURLConnection urlConn=(HttpURLConnection) url[0].openConnection();urlConn.setDoInput(true); //setting inputstream using bytestreamurlConn.setDoOutput(true);urlConn.setRequestMethod("POST");urlConn.setUseCaches(false);urlConn.setRequestProperty("Content-Type","application/x-ww-form-urlencoded"); //urlConn.setRequestProperty("Charset","utf-8");urlConn.connect();bytes_downloaded=GetDownloadedBytes();System.out.println("准备好发送的数据");//第二步:准备好发送的数据Map<String ,String> map=new HashMap<>();map.put("filename",URLEncoder.encode(filename,"UTF-8"));map.put("bytes_downloaded", String.valueOf(bytes_downloaded));JSONArray jsonarray= JSONArray.fromObject(map);//第三步:打开数据通道DataOutputStream dop=new DataOutputStream(urlConn.getOutputStream());dop.write(String.valueOf(jsonarray).getBytes());//第四步:将准备的数据发送给服务器dop.flush();dop.close();long h=urlConn.getHeaderFieldDate("bytes_counts",555);bytes_sum= Integer.parseInt(urlConn.getHeaderField("bytes_counts"));InputStream inputStream=urlConn.getInputStream();File dir=new File(externalstorsgepath+"/nikidata");File file=new File(dir.getAbsolutePath(),filename);String fileexists =dir.getAbsolutePath()+"/"+filename;if (file.exists()) {System.out.println("进入续传");long filelength = file.length();RandomAccessFile fileff = new RandomAccessFile(fileexists,"rw");System.out.println("文件存放位置"+fileexists);System.out.println("续传长度标记"+filelength);byte[] by = new byte[1024];int start =(int)filelength;int amount;System.out.println("从输入流中读数据");fileff.seek(filelength);//fileff.skipBytes(start);System.out.println("当前指针位置"+fileff.getFilePointer());while ((amount = inputStream.read(by)) != -1) {fileff.write(by,0,amount);}System.out.println("结束");fileff.close();} else {System.out.println("文件不存在直接传送");}NotifyMainThread(); //通知主线程,下载进度已经更新} catch (MalformedURLException e) {e.printStackTrace();}catch (ProtocolException e) {e.printStackTrace();}catch (IOException e) {e.printStackTrace();}}@Overridepublic synchronized void start() {super.start();}public int GetDownloadedBytes(){File dir=new File(externalstorsgepath+"/nikidata");File file=new File(dir.getAbsolutePath(),filename);// File file=new File(dir.getAbsolutePath(),"pics.rar");if(!file.exists()){try {file.createNewFile();} catch (IOException e) {e.printStackTrace();}}return (int) file.length();}/*** 判断SDCard是否存在 [当没有外挂SD卡时,内置ROM也被识别为存在sd卡]** @return*/public static boolean isSdCardExist() {return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);}/*** 获取SD卡根目录路径** @return*/public static String getSdCardPath() {boolean exist = isSdCardExist();String sdpath = "";if (exist) {sdpath = String.valueOf(Environment.getExternalStorageDirectory());} else {sdpath = "不适用";}return sdpath;}public void NotifyMainThread(){if(b==null){b=new Bundle();b.putString("message","hello I am a thread");b.putInt("bytes_sum",bytes_sum);b.putInt("bytes_downloaded",bytes_downloaded);Message message=new Message();message.setData(b);handler.sendMessage(message) ;}}
}
效果图就先不上了,因为现在已经六点半了,我赶着去吃饭。
做个总结吧:
1.我原本是想用Socket做长连接的,但是我师父说保持长连接的研发成本比Http要高,因为我用Socket时,确实也遇见了很难搞定的异常:Java.net.SocketException: recvfrom failed: ECONNRESET (Connection reset by peer)。如果有人成功解决过这个异常,希望可以不吝赐教
2.改用Http之后,我认为服务端应该至少传一个参数给客户端,告诉要下载的文件的总字节数,我刚开始是想用JSON,这绝对是序列化的神器呀,对吧?可是我在客户端反序列化的时候,却遇见好几个极难解决的问题,逼得我……都手动写代码去反序列化了。 后来发现,其实我可以直接在response的头部加一个参数,折腾了我那么久!
3.写程序还是要注意保护眼睛,睡个午觉。
谢谢大家的阅读,祝生活愉快~
利用Http在Android客户端与Web服务器之间断点续传中大文件相关推荐
- web服务器是如何维护,我们如何维护Web客户端和Web服务器之间的会话?
以下是维护Web客户端和Web服务器之间的会话的一些选项- 饼干 Web服务器可以将唯一的会话ID作为cookie分配给每个Web客户端,对于来自客户端的后续请求,可以使用接收到的cookie来识别它 ...
- android客户端+JAVA WEB服务器实现json数据解析
首先,项目中使用javaweb作为后台服务器,源码地址:服务器和客户端源码地址. 接下来进入正题. 一.java web服务器 这里就多说了, ...
- Android 客户端 okhttp3 与服务器之间的双向验证
分为三个阶段 一:简单的后台服务器搭建 二:客户端接入okhttp3,并进行的网络请求 三:服务器和客户端的双向验证 第一步: 搭建简单的服务器 1:下载tomcat 2:配置tomcat 3:部 ...
- nginx做反向代理和后端web服务器之间的交互
1.Nginx是什么? Nginx就是反向代理服务器. 首先我们先来看看什么是代理服务器,代理服务器一般是指局域网内部的机器通过代理服务发送请求到互联网上的服务器,代理服务器一般作用于客户端.比如Go ...
- android webserver mysql,Android手机变身Web服务器,BitWebServer简单评测
昨晚逛Play商店发现居然有这软件,支持lighttpd.php.mysql,可以让Android手机变身Web服务器,觉得很有意思,果断下了个玩玩~~ 随便放了一个静态页面,想看效果的可以戳 222 ...
- AndServer,一个Android端的web服务器
版权声明:转载必须注明本文转自严振杰的博客:http://blog.yanzhenjie.com 大家好,今天跟大家介绍一个让原生Android也可以做Web开发的开源项目--AndServer. 开 ...
- Android客户端与PC服务器通过socket进行交互实例
一直以来对Android socket通信都很模糊,今天终于研究了一个网上的例子,自己又修改了下,算是对Android socket通信有点了解了. 下面是具体的代码,说明都在注释中了.需要注意的是, ...
- Android客户端与PC服务器实现Socket通信
Android终端持续扫描AP信息并发送给服务器端的实现.首先基于TCP协议在Android终端和PC两端之间形成网络虚拟链路.使用ServerSocket创建TCP服务器端,然后在Android客户 ...
- unity android服务器端,【深圳Unity3D培训】 Android客户端与PC服务器实现Socket通信
[深圳Unity3D培训] Android客户端与PC服务器实现Socket通信 Android终端连续扫描AP信息并发送给服务器端的完成.起首基于TCP协定在Android终端和PC两头之间构成收集 ...
最新文章
- Django博客系统(404页面展示)
- C语言实现常用数据结构——队列
- AndroidStudio设置不自动弹出 Documentation 窗口
- LIBSVM使用方法
- React-引领未来的用户界面开发框架-读书笔记(六)
- php计算一段时间工作日,PHP计算8小时工作日的一半
- Junit4.x扩展:运行指定方法
- Django缓存设置
- JDBC连接数据库的步骤
- 推荐一款数据恢复软件EasyRecovery
- 配置linux danted socks服务
- 【笔记】定积分的近似计算
- android自动开关机软件,AutoOff(定时关机软件)
- 雷电模拟器7抓包安装证书
- PDF文档翻译(英文翻译为中文)
- RSA的APT峰会会议纪要
- 杰里之drc 限幅器、多带限幅器、压缩器、多带压缩器调节【篇】
- Google chrome谷歌浏览器,打开后是百度搜索或其他搜索怎么办?
- PHP网络在线学习云课堂源码在线教育学习云课堂源码
- wps云文档 wps自动备份怎么设置和取消
热门文章
- 【openbmc添加fru信息通过ipmitool命令读取】
- LeetCode 452 射气球问题
- jmail qq邮箱的服务器,点晴OA发送邮件出现jmail.Message错误8000ffff,提示the message was undeliverable,怎么解决?...
- xlsx表格怎么做汇总统计_Excel表格中如何快速汇总多个数据表中的数据
- UBIFS文件系统分析6 - LPT分析1 .
- [Docker] Dockerfile 记录
- 设定网页为浏览器首页
- PyCharm可用到2099年玫瑰花樱花树五环
- java后端使用树结构表示省,市,县的实例
- echarts初始化中国地图(Map)