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
• 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
•      }
  • }