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