0.使用http协议是不能实现断点上传的,对于文件大小不一,与实际需求可以使用Socket断点上传
1.上传原理:Android客户端发送上传文件头字段给服务器,服务器建立socket连接,监听一个端口(7878),然后建立一个outStream接收到客户端的字段信息,服务器判断文件是否在服务器上,文件是否有上传的记录,若是文件不存在,服务器则返回一个id(断点数据)通知客户端从什么位置开始上传,客户端通过inputStream获得服务器返回的字段,开始从获得的位置开始上传文件
2.实例演示
(0)服务器端代码
• public class
• {
• //线程池
• private
• //监听端口
• private int
• //退出
• private boolean quit = false;
• private
• //存放断点数据
• private Map<Long, FileLog> datas = new
•
• public FileServer(int
• {
• this.port = port;
• //创建线程池,池中具有(cpu个数*50)条线程
• 50);
• }
•
• /**
• * 退出
• */
• public void
• {
• this.quit = true;
• try
• {
• server.close();
• }
• catch
• {
• e.printStackTrace();
• }
• }
•
• /**
• * 启动服务
• * @throws Exception
• */
• public void start() throws
• {
• //实现端口监听
• new
• while(!quit)
• {
• try
• {
• Socket socket = server.accept();
• //为支持多用户并发访问,采用线程池管理每一个用户的连接请求
• new
• }
• catch
• {
• e.printStackTrace();
• }
• }
• }
•
• private final class SocketTask implements
• {
• private Socket socket = null;
• public
• {
• this.socket = socket;
• }
•
• @Override
• public void
• {
• try
• {
• "accepted connection "+ socket.getInetAddress()+ ":"+ socket.getPort());
• //这里的输入流PushbackInputStream可以回退到之前的某个点开始进行读取
• new
• //得到客户端发来的第一行协议数据:Content-Length=143253434;filename=xxx.3gp;sourceid=
• //如果用户初次上传文件,sourceid的值为空。
• String head = StreamTool.readLine(inStream);
• System.out.println(head);
• if(head!=null)
• {
• //下面从协议数据中提取各项参数值
• ";");
• 0].substring(items[0].indexOf("=")+1);
• 1].substring(items[1].indexOf("=")+1);
• 2].substring(items[2].indexOf("=")+1);
• //生产资源id,如果需要唯一性,可以采用UUID
• long
• null;
• if(sourceid!=null && !"".equals(sourceid))
• {
• id = Long.valueOf(sourceid);
• //查找上传的文件是否存在上传记录
• log = find(id);
• }
• null;
• int position = 0;
• //如果上传的文件不存在上传记录,为文件添加跟踪记录
• if(log==null)
• {
• new SimpleDateFormat("yyyy/MM/dd/HH/mm").format(new
• //设置存放的位置与当前应用的位置有关
• new File("file/"+ path);
• if(!dir.exists()) dir.mkdirs();
• new
• //如果上传的文件发生重名,然后进行改名
• if(file.exists())
• {
• 0, filename.indexOf(".")-1)+ dir.listFiles().length+ filename.substring(filename.indexOf("."));
• new
• }
• save(id, file);
• }
• // 如果上传的文件存在上传记录,读取上次的断点位置
• else
• {
• //从上传记录中得到文件的路径
• new
• if(file.exists())
• {
• new File(file.getParentFile(), file.getName()+".log");
• if(logFile.exists())
• {
• new
• new
• //读取断点位置
• "length"));
• }
• }
• }
•
• OutputStream outStream = socket.getOutputStream();
• "sourceid="+ id+ ";position="+ position+ "/r/n";
• //服务器收到客户端的请求信息后,给客户端返回响应信息:sourceid=1274773833264;position=0
• //sourceid由服务生成,唯一标识上传的文件,position指示客户端从文件的什么位置开始上传
• outStream.write(response.getBytes());
• //
• new RandomAccessFile(file, "rwd");
• //设置文件长度
• if(position==0) fileOutStream.setLength(Integer.valueOf(filelength));
• //移动文件指定的位置开始写入数据
• fileOutStream.seek(position);
• byte[] buffer = new byte[1024];
• int len = -1;
• int
• //从输入流中读取数据写入到文件中
• while( (len=inStream.read(buffer)) != -1)
• {
• 0, len);
• length += len;
• new
• "length", String.valueOf(length));
• new FileOutputStream(new File(file.getParentFile(), file.getName()+".log"));
• //实时记录文件的最后保存位置
• null);
• logFile.close();
• }
• //如果长传长度等于实际长度则表示长传成功
• if(length==fileOutStream.length()) delete(id);
• fileOutStream.close();
• inStream.close();
• outStream.close();
• null;
•
• }
• }
• catch
• {
• e.printStackTrace();
• }
• finally
• {
• try
• {
• if(socket!=null
• }
• catch
• {
• e.printStackTrace();
• }
• }
• }
• }
•
• public
• {
• return
• }
• //保存上传记录
• public void
• {
• //日后可以改成通过数据库存放
• new
• }
• //当文件上传完毕,删除记录
• public void delete(long
• {
• if(datas.containsKey(sourceid)) datas.remove(sourceid);
• }
•
• private class
• private
• private
• public
• return
• }
• public void
• this.id = id;
• }
• public
• return
• }
• public void
• this.path = path;
• }
• public
• this.id = id;
• this.path = path;
• }
• }
• }
1. public class ServerWindow extends
2. {
3. private FileServer s = new FileServer(7878);
4. private
5.
6. public
7. {
8. super(title);
9. new
10. add(label, BorderLayout.PAGE_START);
11. "服务器已经启动");
12. this.addWindowListener(new
13. {
14. @Override
15. public void
16. {
17. new Thread(new
18. {
19. @Override
20. public void
21. {
22. try
23. {
24. s.start();
25. }
26. catch
27. {
28. e.printStackTrace();
29. }
30. }
31. }).start();
32. }
33.
34. @Override
35. public void
36. }
37.
38. @Override
39. public void
40. }
41.
42. @Override
43. public void
44. }
45.
46. @Override
47. public void
48. s.quit();
49. 0);
50. }
51.
52. @Override
53. public void
54. }
55.
56. @Override
57. public void
58. }
59. });
60. }
61. /**
62. * @param args
63. */
64. public static void
65. {
66. new ServerWindow("文件上传服务端");
67. 300, 300);
68. true);
69. }
70. }
1. public class
2. {
3. public static void
4. {
5. try
6. {
7. //这里的套接字根据实际服务器更改
8. new Socket("127.0.0.1", 7878);
9. OutputStream outStream = socket.getOutputStream();
10. "QQWubiSetup.exe";
11. new
12. //构造上传文件头,上传的时候会判断上传的文件是否存在,是否存在上传记录
13. //若是不存在则服务器会自动生成一个id,给客户端返回
14. "Content-Length="+ file.length() + ";filename="+ filename + ";sourceid=1278916111468/r/n";
15. outStream.write(head.getBytes());
16.
17. new
18. String response = StreamTool.readLine(inStream);
19. System.out.println(response);
20. ";");
21. //构造开始上传文件的位置
22. 1].substring(items[1].indexOf("=")+1);
23. //以读的方式开始访问
24. new RandomAccessFile(file, "r");
25. fileOutStream.seek(Integer.valueOf(position));
26. byte[] buffer = new byte[1024];
27. int len = -1;
28. int i = 0;
29. while( (len = fileOutStream.read(buffer)) != -1)
30. {
31. 0, len);
32. i++;
33. //if(i==10) break;
34. }
35. fileOutStream.close();
36. outStream.close();
37. inStream.close();
38. socket.close();
39. }
40. catch
41. {
42. e.printStackTrace();
43. }
44. }
45. /**
46. * 读取流
47. * @param inStream
48. * @return 字节数组
49. * @throws Exception
50. */
51. public static byte[] readStream(InputStream inStream) throws
52. {
53. new
54. byte[] buffer = new byte[1024];
55. int len = -1;
56. while( (len=inStream.read(buffer)) != -1)
57. {
58. 0, len);
59. }
60. outSteam.close();
61. inStream.close();
62. return
63. }
64. }
1. public class
2. {
3.
4. public static void save(File file, byte[] data) throws
5. {
6. new
7. outStream.write(data);
8. outStream.close();
9. }
10.
11. public static String readLine(PushbackInputStream in) throws
12. {
13. char buf[] = new char[128];
14. int
15. int offset = 0;
16. int
17. while (true) {
18. switch
19. {
20. case -1:
21. case '/n':
22. break
23. case '/r':
24. int
25. if ((c2 != '/n') && (c2 != -1)) in.unread(c2);
26. break
27. default:
28. if (--room < 0) {
29. char[] lineBuffer = buf;
30. new char[offset + 128];
31. 1;
32. 0, buf, 0, offset);
33.
34. }
35. char) c;
36. break;
37. }
38. }
39. if ((c == -1) && (offset == 0)) return null;
40. return String.copyValueOf(buf, 0, offset);
41. }
42.
43. /**
44. * 读取流
45. * @param inStream
46. * @return 字节数组
47. * @throws Exception
48. */
49. public static byte[] readStream(InputStream inStream) throws
50. {
51. new
52. byte[] buffer = new byte[1024];
53. int len = -1;
54. while( (len=inStream.read(buffer)) != -1){
55. 0, len);
56. }
57. outSteam.close();
58. inStream.close();
59. return
60. }
61. }
(1)Android客户端代码:
1. public class UploadActivity extends
2. {
3. private
4. private
5. private
6. private
7.
8. @Override
9. public void
10. {
11. super.onCreate(savedInstanceState);
12. setContentView(R.layout.main);
13.
14. new UploadLogService(this);
15. this.findViewById(R.id.filename);
16. this.findViewById(R.id.uploadbar);
17. this.findViewById(R.id.result);
18. this.findViewById(R.id.button);
19. new
20. {
21. @Override
22. public void
23. {
24. String filename = filenameText.getText().toString();
25. //判断SDCard是否存在
26. if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
27. {
28. //取得SDCard的目录
29. new
30. if(uploadFile.exists())
31. {
32. uploadFile(uploadFile);
33. }
34. else
35. {
36. this, R.string.filenotexsit, 1).show();
37. }
38. }
39. else
40. {
41. this, R.string.sdcarderror, 1).show();
42. }
43. }
44. });
45. }
46. /**
47. * 使用Handler给创建他的线程发送消息,
48. * 匿名内部类
49. */
50. private Handler handler = new
51. {
52. @Override
53. public void
54. {
55. //获得上传长度的进度
56. int length = msg.getData().getInt("size");
57. uploadbar.setProgress(length);
58. float num = (float)uploadbar.getProgress()/(float)uploadbar.getMax();
59. int result = (int)(num * 100);
60. //设置显示结果
61. "%");
62. //上传成功
63. if(uploadbar.getProgress()==uploadbar.getMax())
64. {
65. this, R.string.success, 1).show();
66. }
67. }
68. };
69.
70. /**
71. * 上传文件,应该启动一个线程,使用Handler来避免UI线程ANR错误
72. * @param final uploadFile
73. */
74. private void uploadFile(final
75. {
76. new Thread(new
77. {
78. @Override
79. public void
80. {
81. try
82. {
83. //设置长传文件的最大刻度
84. int)uploadFile.length());
85. //判断文件是否已有上传记录
86. String souceid = logService.getBindId(uploadFile);
87. //构造拼接协议
88. "Content-Length="+ uploadFile.length() + ";filename="+ uploadFile.getName() + ";sourceid="+
89. null? "" : souceid)+"/r/n";
90. //通过Socket取得输出流
91. new Socket("192.168.1.100", 7878);
92. OutputStream outStream = socket.getOutputStream();
93. outStream.write(head.getBytes());
94.
95. new
96. //获取到字符流的id与位置
97. String response = StreamTool.readLine(inStream);
98. ";");
99. 0].substring(items[0].indexOf("=")+1);
100. 1].substring(items[1].indexOf("=")+1);
101. //代表原来没有上传过此文件,往数据库添加一条绑定记录
102. if(souceid==null)
103. {
104. logService.save(responseid, uploadFile);
105. }
106. new RandomAccessFile(uploadFile, "r");
107. fileOutStream.seek(Integer.valueOf(position));
108. byte[] buffer = new byte[1024];
109. int len = -1;
110. //初始化长传的数据长度
111. int
112. while( (len = fileOutStream.read(buffer)) != -1)
113. {
114. 0, len);
115. //设置长传数据长度
116. length += len;
117. new
118. "size", length);
119. handler.sendMessage(msg);
120. }
121. fileOutStream.close();
122. outStream.close();
123. inStream.close();
124. socket.close();
125. //判断上传完则删除数据
126. if(length==uploadFile.length())
127. logService.delete(uploadFile);
128. }
129. catch
130. {
131. e.printStackTrace();
132. }
133. }
134. }).start();
135. }
136. }
1. public class DBOpenHelper extends
2. {
3. public
4. {
5. super(context, "upload.db", null, 1);
6. }
7. @Override
8. public void
9. {
10. "CREATE TABLE uploadlog (_id integer primary key autoincrement, uploadfilepath varchar(100), sourceid varchar(10))");
11. }
12. @Override
13. public void onUpgrade(SQLiteDatabase db, int oldVersion, int
14. {
15. "DROP TABLE IF EXISTS uploadlog");
16. onCreate(db);
17. }
18. }
1. public class
2. {
3. private
4. //给出上下文对象
5. public
6. {
7. this.dbOpenHelper = new
8. }
9. //保存上传文件断点数据
10. public void
11. {
12. SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
13. "insert into uploadlog(uploadfilepath, sourceid) values(?,?)",
14. new
15. }
16. //删除上传文件断点数据
17. public void
18. {
19. SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
20. "delete from uploadlog where uploadfilepath=?", new
21. }
22. //根据文件的上传路径得到绑定的id
23. public
24. {
25. SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
26. "select sourceid from uploadlog where uploadfilepath=?",
27. new
28. if(cursor.moveToFirst())
29. {
30. return cursor.getString(0);
31. }
32. return null;
33. }
34. }
• public class
• {
•
• public static void save(File file, byte[] data) throws
• {
• new
• outStream.write(data);
• outStream.close();
• }
•
• public static String readLine(PushbackInputStream in) throws
• {
• char buf[] = new char[128];
• int
• int offset = 0;
• int
• loop: while (true) {
• switch
• case -1:
• case '/n':
• break
• case '/r':
• int
• if ((c2 != '/n') && (c2 != -1)) in.unread(c2);
• break
• default:
• if (--room < 0) {
• char[] lineBuffer = buf;
• new char[offset + 128];
• 1;
• 0, buf, 0, offset);
•
• }
• char) c;
• break;
• }
• }
• if ((c == -1) && (offset == 0)) return null;
• return String.copyValueOf(buf, 0, offset);
• }
•
• /**
• * 读取流
• * @param inStream
• * @return 字节数组
• * @throws Exception
• */
• public static byte[] readStream(InputStream inStream) throws
• {
• new
• byte[] buffer = new byte[1024];
• int len = -1;
• while( (len=inStream.read(buffer)) != -1)
• {
• 0, len);
• }
• outSteam.close();
• inStream.close();
• return
• }
• }