http://www.linuxidc.com/Linux/2012-03/55567.htm

http://blog.csdn.net/shimiso/article/details/8529633/

Android中上传文件可以采用HTTP方式,也可以采用Socket方式,但是HTTP方式不能上传大文件,这里介绍一种通过Socket方式来进行断点续传的方式,服务端会记录下文件的上传进度,当某一次上传过程意外终止后,下一次可以继续上传,这里用到的其实还是J2SE里的知识。

这个上传程序的原理是:客户端第一次上传时向服务端发送“Content-Length=35;filename=WinRAR_3.90_SC.exe;sourceid=“这种格式的字符串,服务端收到后会查找该文件是否有上传记录,如果有就返回已经上传的位置,否则返回新生成的sourceid以及position为0,类似”sourceid=2324838389;position=0“这样的字符串,客户端收到返回后的字符串后再从指定的位置开始上传文件。

首先是服务端代码:

SocketServer.java

  1. package com.android.socket.server;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.FileOutputStream;
  5. import java.io.IOException;
  6. import java.io.OutputStream;
  7. import java.io.PushbackInputStream;
  8. import java.io.RandomAccessFile;
  9. import java.net.ServerSocket;
  10. import java.net.Socket;
  11. import java.text.SimpleDateFormat;
  12. import java.util.Date;
  13. import java.util.HashMap;
  14. import java.util.Map;
  15. import java.util.Properties;
  16. import java.util.concurrent.ExecutorService;
  17. import java.util.concurrent.Executors;
  18. import com.android.socket.utils.StreamTool;
  19. public class SocketServer {
  20. private ExecutorService executorService;// 线程池
  21. private ServerSocket ss = null;
  22. private int port;// 监听端口
  23. private boolean quit;// 是否退出
  24. private Map<Long, FileLog> datas = new HashMap<Long, FileLog>();// 存放断点数据,最好改为数据库存放
  25. public SocketServer(int port) {
  26. this.port = port;
  27. // 初始化线程池
  28. executorService = Executors.newFixedThreadPool(Runtime.getRuntime()
  29. .availableProcessors() * );
  30. }
  31. // 启动服务
  32. public void start() throws Exception {
  33. ss = new ServerSocket(port);
  34. while (!quit) {
  35. Socket socket = ss.accept();// www.linuxidc.com接受客户端的请求
  36. // 为支持多用户并发访问,采用线程池管理每一个用户的连接请求
  37. executorService.execute(new SocketTask(socket));// 启动一个线程来处理请求
  38. }
  39. }
  40. // 退出
  41. public void quit() {
  42. this.quit = true;
  43. try {
  44. ss.close();
  45. catch (IOException e) {
  46. e.printStackTrace();
  47. }
  48. }
  49. public static void main(String[] args) throws Exception {
  50. SocketServer server = );
  51. server.start();
  52. }
  53. private class SocketTask implements Runnable {
  54. private Socket socket;
  55. public SocketTask(Socket socket) {
  56. this.socket = socket;
  57. }
  58. @Override
  59. public void run() {
  60. try {
  61. System.out.println("accepted connenction from "
  62. + socket.getInetAddress() + " @ " + socket.getPort());
  63. PushbackInputStream inStream = new PushbackInputStream(
  64. socket.getInputStream());
  65. // 得到客户端发来的第一行协议数据:Content-Length=143253434;filename=xxx.3gp;sourceid=
  66. // 如果用户初次上传文件,sourceid的值为空。
  67. String head = StreamTool.readLine(inStream);
  68. System.out.println(head);
  69. if (head != null) {
  70. // 下面从协议数据中读取各种参数值
  71. String[] items = head.split(";");
  72. String filelength = items[].substring(items[].indexOf();
  73. String filename = items[].substring(items[].indexOf();
  74. String sourceid = items[].substring(items[].indexOf();
  75. Long id = System.currentTimeMillis();
  76. FileLog log = null;
  77. if (null != sourceid && !"".equals(sourceid)) {
  78. id = Long.valueOf(sourceid);
  79. log = find(id);//查找上传的文件是否存在上传记录
  80. }
  81. File file = null;
  82. ;
  83. if(log==null){//如果上传的文件不存在上传记录,为文件添加跟踪记录
  84. String path = new SimpleDateFormat("yyyy/MM/dd/HH/mm").format(new Date());
  85. File dir = new File("file/"+ path);
  86. if(!dir.exists()) dir.mkdirs();
  87. file = new File(dir, filename);
  88. if(file.exists()){//如果上传的文件发生重名,然后进行改名
  89. filename = filename.substring(, filename.indexOf()+ dir.listFiles().length+ filename.substring(filename.indexOf("."));
  90. file = new File(dir, filename);
  91. }
  92. save(id, file);
  93. }else{// 如果上传的文件存在上传记录,读取上次的断点位置
  94. file = new File(log.getPath());//从上传记录中得到文件的路径
  95. if(file.exists()){
  96. File logFile = new File(file.getParentFile(), file.getName()+".log");
  97. if(logFile.exists()){
  98. Properties properties = new Properties();
  99. properties.load(new FileInputStream(logFile));
  100. position = Integer.valueOf(properties.getProperty("length"));//读取断点位置
  101. }
  102. }
  103. }
  104. OutputStream outStream = socket.getOutputStream();
  105. String response = "sourceid="+ id+ ";position="+ position+ "\r\n";
  106. //服务器收到客户端的请求信息后,给客户端返回响应信息:sourceid=1274773833264;position=0
  107. //sourceid由服务生成,唯一标识上传的文件,position指示客户端从文件的什么位置开始上传
  108. outStream.write(response.getBytes());
  109. RandomAccessFile fileOutStream = new RandomAccessFile(file, "rwd");
  110. ) fileOutStream.setLength(Integer.valueOf(filelength));//设置文件长度
  111. fileOutStream.seek(position);//移动文件指定的位置开始写入数据
  112. ];
  113. ;
  114. int length = position;
  115. ){//从输入流中读取数据写入到文件中
  116. fileOutStream.write(buffer, , len);
  117. length += len;
  118. Properties properties = new Properties();
  119. properties.put("length", String.valueOf(length));
  120. FileOutputStream logFile = new FileOutputStream(new File(file.getParentFile(), file.getName()+".log"));
  121. properties.store(logFile, null);//实时记录文件的最后保存位置
  122. logFile.close();
  123. }
  124. if(length==fileOutStream.length()) delete(id);
  125. fileOutStream.close();
  126. inStream.close();
  127. outStream.close();
  128. file = null;
  129. }
  130. catch (Exception e) {
  131. e.printStackTrace();
  132. finally {
  133. try {
  134. if(socket != null && !socket.isClosed()) socket.close();
  135. catch (IOException e) {}
  136. }
  137. }
  138. }
  139. public FileLog find(Long sourceid) {
  140. return datas.get(sourceid);
  141. }
  142. // 保存上传记录
  143. public void save(Long id, File saveFile) {
  144. // 日后可以改成通过数据库存放
  145. datas.put(id, new FileLog(id, saveFile.getAbsolutePath()));
  146. }
  147. // 当文件上传完毕,删除记录
  148. public void delete(long sourceid) {
  149. if (datas.containsKey(sourceid))
  150. datas.remove(sourceid);
  151. }
  152. private class FileLog {
  153. private Long id;
  154. private String path;
  155. public FileLog(Long id, String path) {
  156. super();
  157. this.id = id;
  158. this.path = path;
  159. }
  160. public Long getId() {
  161. return id;
  162. }
  163. public void setId(Long id) {
  164. this.id = id;
  165. }
  166. public String getPath() {
  167. return path;
  168. }
  169. public void setPath(String path) {
  170. this.path = path;
  171. }
  172. }
  173. }

ServerWindow.java

  1. package com.android.socket.server;
  2. import java.awt.BorderLayout;
  3. import java.awt.Frame;
  4. import java.awt.Label;
  5. import java.awt.event.WindowEvent;
  6. import java.awt.event.WindowListener;
  7. public class ServerWindow extends Frame{
  8. private SocketServer server;
  9. private Label label;
  10. public ServerWindow(String title){
  11. super(title);
  12. server = );
  13. label = new Label();
  14. add(label, BorderLayout.PAGE_START);
  15. label.setText("服务器已经启动www.linuxidc.com");
  16. this.addWindowListener(new WindowListener() {
  17. @Override
  18. public void windowOpened(WindowEvent e) {
  19. new Thread(new Runnable() {
  20. @Override
  21. public void run() {
  22. try {
  23. server.start();
  24. catch (Exception e) {
  25. e.printStackTrace();
  26. }
  27. }
  28. }).start();
  29. }
  30. @Override
  31. public void windowIconified(WindowEvent e) {
  32. }
  33. @Override
  34. public void windowDeiconified(WindowEvent e) {
  35. }
  36. @Override
  37. public void windowDeactivated(WindowEvent e) {
  38. }
  39. @Override
  40. public void windowClosing(WindowEvent e) {
  41. server.quit();
  42. System.exit();
  43. }
  44. @Override
  45. public void windowClosed(WindowEvent e) {
  46. }
  47. @Override
  48. public void windowActivated(WindowEvent e) {
  49. }
  50. });
  51. }
  52. /**
  53. * @param args
  54. */
  55. public static void main(String[] args) {
  56. ServerWindow window = new ServerWindow("文件上传服务端");
  57. window.setSize(, );
  58. window.setVisible(true);
  59. }
  60. }

工具类StreamTool.java

  1. package com.android.socket.utils;
  2. import java.io.ByteArrayOutputStream;
  3. import java.io.File;
  4. import java.io.FileOutputStream;
  5. import java.io.IOException;
  6. import java.io.InputStream;
  7. import java.io.PushbackInputStream;
  8. public class StreamTool {
  9. public static void save(File file, byte[] data) throws Exception {
  10. FileOutputStream outStream = new FileOutputStream(file);
  11. outStream.write(data);
  12. outStream.close();
  13. }
  14. public static String readLine(PushbackInputStream in) throws IOException {
  15. ];
  16. int room = buf.length;
  17. ;
  18. int c;
  19. loop:       while (true) {
  20. switch (c = in.read()) {
  21. :
  22. case '\n':
  23. break loop;
  24. case '\r':
  25. int c2 = in.read();
  26. )) in.unread(c2);
  27. break loop;
  28. default:
  29. ) {
  30. char[] lineBuffer = buf;
  31. buf = ];
  32. room = buf.length - offset - ;
  33. System.arraycopy(lineBuffer, , buf, , offset);
  34. }
  35. buf[offset++] = (char) c;
  36. break;
  37. }
  38. }
  39. ) && (offset == )) return null;
  40. , offset);
  41. }
  42. /**
  43. * 读取流
  44. * @param inStream
  45. * @return 字节数组
  46. * @throws Exception
  47. */
  48. public static byte[] readStream(InputStream inStream) throws Exception{
  49. ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
  50. ];
  51. ;
  52. ){
  53. outSteam.write(buffer, , len);
  54. }
  55. outSteam.close();
  56. inStream.close();
  57. return outSteam.toByteArray();
  58. }
  59. }

Android客户端代码:

Android应用开发之使用Socket进行大文件断点上传续传的更多相关文章

  1. Android中Socket大文件断点上传

    原文:http://blog.csdn.net/shimiso/article/details/8529633 什么是Socket? 所谓Socket通常也称作“套接字”,用于描述IP地址和端口,是一 ...

  2. asp.net 如何实现大文件断点上传功能?

    之前仿造uploadify写了一个HTML5版的文件上传插件,没看过的朋友可以点此先看一下~得到了不少朋友的好评,我自己也用在了项目中,不论是用户头像上传,还是各种媒体文件的上传,以及各种个性的业务需 ...

  3. 大文件断点上传 js+php

    /* * js */ function PostFile(file, i, t) {    console.log(1);  var name = file.name, //文件名 size = fi ...

  4. ASP.NET大文件断点上传

    HTML部分 <%@PageLanguage="C#"AutoEventWireup="true"CodeBehind="index.aspx. ...

  5. 利用Socket进行大文件传输

    分类: WINDOWS 最近接触到利用socket进行大文件传输的技术,有些心得,与大家分享.首先看看这个过程是怎么进行的(如下图):      所以,我们需要三个socket在窗体加载的时候初始化: ...

  6. 基于socket实现大文件上传

    import socket 1.客户端: 操作流程: 先拿到文件--->获取文件大小---->创建字典 1.制作表头 header  如何得到 他是一个二进制字符串 序列化得到 字典字符串 ...

  7. ios开发网络学习四:NSURLConnection大文件断点下载

    #import "ViewController.h" @interface ViewController ()<NSURLConnectionDataDelegate> ...

  8. 使用webuploader组件实现大文件分片上传,断点续传

    本人在2010年时使用swfupload为核心进行文件的批量上传的解决方案.见文章:WEB版一次选择多个文件进行批量上传(swfupload)的解决方案. 本人在2013年时使用plupload为核心 ...

  9. Java 断点下载(下载续传)服务端及客户端(Android)代码

    原文: Java 断点下载(下载续传)服务端及客户端(Android)代码 - Stars-One的杂货小窝 最近在研究断点下载(下载续传)的功能,此功能需要服务端和客户端进行对接编写,本篇也是记录一 ...

随机推荐

  1. HEXO next live2d插件删除问题

    title: HEXO next live2d插件删除问题 date: 2018-03-06 13:09:12 updated: tags: [hexo,next,建站,学习,前端技术,疑问] des ...

  2. 17、bootStrap组件

    1.bootStrap组件 无数可复用的组件,包括字体图标.下拉菜单.导航.警告框.弹出框等更多功能. 2.字体图标 ①不要和其他图标混合使用 ②只能对内容为空的元素起作用 3.下拉菜单 <di ...

  3. 爬虫:Scrapy8 - Item Pipeline

    当 Item 在 Spider 中被收集之后,它将会被传递到 Item Pipeline,一些组件会按照一定的顺序执行对 Item 的处理. 每个 item pipeline 组件(有时也称之为“It ...

  4. user-select & css

    user-select & css https://developer.mozilla.org/en-US/docs/Web/CSS/user-select https://css-trick ...

  5. POJ 1375 Intervals | 解析几何

    参考了这个博客 #include<cstdio> #include<algorithm> #include<cstring> #include<cmath&g ...

  6. POJ 3421 X-factor Chains | 数论

    题意: 给一个x,求最长的排列满足开头是1,结尾是x,前一个数是后一个数的因子 输出长度和这样序列的个数 题解: 把x分解质因数,质因数个数就是答案,接下来考虑怎么求个数 显然这是一个可重集合全排列问 ...

  7. hdu 2993 斜率dp

    思路:直接通过斜率优化进行求解. #include<iostream> #include<cstdio> #include<algorithm> #include& ...

  8. 日常收集整理些js经典实例

    跨浏览器添加事件 //跨浏览器添加事件 function addEvent(obj,type,fn){ if(obj.addEventListener){ obj.addEventListener(t ...

  9. Windows1小时后关机命令

    shutdown -s -t 3600 1.注销当前用户 shutdown - l 该命令只能注销本机用户,对远程计算机不适用. 2.关闭本地计算机 shutdown - s 3.重启本地计算机 sh ...

  10. Math对象常用方法

    1.Math.ceil(x) 返回x的向上取整. var a=Math.ceil(9.1); var b=Math.ceil(-9.1) console.log(a); console.log(b); ...