- 浏览: 2108605 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
wahahachuang5:
web实时推送技术使用越来越广泛,但是自己开发又太麻烦了,我觉 ...
细说websocket - php篇 -
wahahachuang8:
挺好的,学习了
细说websocket - php篇 -
jacking124:
学习了!支持你,继续
初窥Linux 之 我最常用的20条命令 -
aliahhqcheng:
应该是可以实现的,没有看过源码。你可以参考下:http://w ...
Jackson 框架,轻易转换JSON
Android应用开发之使用Socket进行大文件断点上传续传
在Android中上传文件可以采用HTTP方式,也可以采用Socket方式,但是HTTP方式不能上传大文件,这里介绍一种通过Socket方式来进行断点续传的方式,服务端会记录下文件的上传进度,当某一次上传过程意外终止后,下一次可以继续上传,这里用到的其实还是J2SE里的知识。
工具类StreamTool.java
Android客户端代码:
数据文件values/strings.xml
AndroidManifest.xml
UploadActivity.java
UploadLogService.java
DBOpenHelper.java
StreamTool.java上面已经给出过了。
这个上传程序的原理是:客户端第一次上传时向服务端发送“Content-Length=35;filename=WinRAR_3.90_SC.exe;sourceid=“这种格式的字符串,服务端收到后会查找该文件是否有上传记录,如果有就返回已经上传的位置,否则返回新生成的sourceid以及position为0,类似”sourceid=2324838389;position=0“这样的字符串,客户端收到返回后的字符串后再从指定的位置开始上传文件。
首先是服务端代码:
SocketServer.java
- packagecom.android.socket.server;
- importjava.io.File;
- importjava.io.FileInputStream;
- importjava.io.FileOutputStream;
- importjava.io.IOException;
- importjava.io.OutputStream;
- importjava.io.PushbackInputStream;
- importjava.io.RandomAccessFile;
- importjava.net.ServerSocket;
- importjava.net.Socket;
- importjava.text.SimpleDateFormat;
- importjava.util.Date;
- importjava.util.HashMap;
- importjava.util.Map;
- importjava.util.Properties;
- importjava.util.concurrent.ExecutorService;
- importjava.util.concurrent.Executors;
- importcom.android.socket.utils.StreamTool;
- publicclassSocketServer{
- privateExecutorServiceexecutorService;//线程池
- privateServerSocketss=null;
- privateintport;//监听端口
- privatebooleanquit;//是否退出
- privateMap<Long,FileLog>datas=newHashMap<Long,FileLog>();//存放断点数据,最好改为数据库存放
- publicSocketServer(intport){
- this.port=port;
- //初始化线程池
- executorService=Executors.newFixedThreadPool(Runtime.getRuntime()
- .availableProcessors()*50);
- }
- //启动服务
- publicvoidstart()throwsException{
- ss=newServerSocket(port);
- while(!quit){
- Socketsocket=ss.accept();//www.linuxidc.com接受客户端的请求
- //为支持多用户并发访问,采用线程池管理每一个用户的连接请求
- executorService.execute(newSocketTask(socket));//启动一个线程来处理请求
- }
- }
- //退出
- publicvoidquit(){
- this.quit=true;
- try{
- ss.close();
- }catch(IOExceptione){
- e.printStackTrace();
- }
- }
- publicstaticvoidmain(String[]args)throwsException{
- SocketServerserver=newSocketServer(8787);
- server.start();
- }
- privateclassSocketTaskimplementsRunnable{
- privateSocketsocket;
- publicSocketTask(Socketsocket){
- this.socket=socket;
- }
- @Override
- publicvoidrun(){
- try{
- System.out.println("acceptedconnenctionfrom"
- +socket.getInetAddress()+"@"+socket.getPort());
- PushbackInputStreaminStream=newPushbackInputStream(
- socket.getInputStream());
- //得到客户端发来的第一行协议数据:Content-Length=143253434;filename=xxx.3gp;sourceid=
- //如果用户初次上传文件,sourceid的值为空。
- Stringhead=StreamTool.readLine(inStream);
- System.out.println(head);
- if(head!=null){
- //下面从协议数据中读取各种参数值
- String[]items=head.split(";");
- Stringfilelength=items[0].substring(items[0].indexOf("=")+1);
- Stringfilename=items[1].substring(items[1].indexOf("=")+1);
- Stringsourceid=items[2].substring(items[2].indexOf("=")+1);
- Longid=System.currentTimeMillis();
- FileLoglog=null;
- if(null!=sourceid&&!"".equals(sourceid)){
- id=Long.valueOf(sourceid);
- log=find(id);//查找上传的文件是否存在上传记录
- }
- Filefile=null;
- intposition=0;
- if(log==null){//如果上传的文件不存在上传记录,为文件添加跟踪记录
- Stringpath=newSimpleDateFormat("yyyy/MM/dd/HH/mm").format(newDate());
- Filedir=newFile("file/"+path);
- if(!dir.exists())dir.mkdirs();
- file=newFile(dir,filename);
- if(file.exists()){//如果上传的文件发生重名,然后进行改名
- filename=filename.substring(0,filename.indexOf(".")-1)+dir.listFiles().length+filename.substring(filename.indexOf("."));
- file=newFile(dir,filename);
- }
- save(id,file);
- }else{//如果上传的文件存在上传记录,读取上次的断点位置
- file=newFile(log.getPath());//从上传记录中得到文件的路径
- if(file.exists()){
- FilelogFile=newFile(file.getParentFile(),file.getName()+".log");
- if(logFile.exists()){
- Propertiesproperties=newProperties();
- properties.load(newFileInputStream(logFile));
- position=Integer.valueOf(properties.getProperty("length"));//读取断点位置
- }
- }
- }
- OutputStreamoutStream=socket.getOutputStream();
- Stringresponse="sourceid="+id+";position="+position+"\r\n";
- //服务器收到客户端的请求信息后,给客户端返回响应信息:sourceid=1274773833264;position=0
- //sourceid由服务生成,唯一标识上传的文件,position指示客户端从文件的什么位置开始上传
- outStream.write(response.getBytes());
- RandomAccessFilefileOutStream=newRandomAccessFile(file,"rwd");
- if(position==0)fileOutStream.setLength(Integer.valueOf(filelength));//设置文件长度
- fileOutStream.seek(position);//移动文件指定的位置开始写入数据
- byte[]buffer=newbyte[1024];
- intlen=-1;
- intlength=position;
- while((len=inStream.read(buffer))!=-1){//从输入流中读取数据写入到文件中
- fileOutStream.write(buffer,0,len);
- length+=len;
- Propertiesproperties=newProperties();
- properties.put("length",String.valueOf(length));
- FileOutputStreamlogFile=newFileOutputStream(newFile(file.getParentFile(),file.getName()+".log"));
- properties.store(logFile,null);//实时记录文件的最后保存位置
- logFile.close();
- }
- if(length==fileOutStream.length())delete(id);
- fileOutStream.close();
- inStream.close();
- outStream.close();
- file=null;
- }
- }catch(Exceptione){
- e.printStackTrace();
- }finally{
- try{
- if(socket!=null&&!socket.isClosed())socket.close();
- }catch(IOExceptione){}
- }
- }
- }
- publicFileLogfind(Longsourceid){
- returndatas.get(sourceid);
- }
- //保存上传记录
- publicvoidsave(Longid,FilesaveFile){
- //日后可以改成通过数据库存放
- datas.put(id,newFileLog(id,saveFile.getAbsolutePath()));
- }
- //当文件上传完毕,删除记录
- publicvoiddelete(longsourceid){
- if(datas.containsKey(sourceid))
- datas.remove(sourceid);
- }
- privateclassFileLog{
- privateLongid;
- privateStringpath;
- publicFileLog(Longid,Stringpath){
- super();
- this.id=id;
- this.path=path;
- }
- publicLonggetId(){
- returnid;
- }
- publicvoidsetId(Longid){
- this.id=id;
- }
- publicStringgetPath(){
- returnpath;
- }
- publicvoidsetPath(Stringpath){
- this.path=path;
- }
- }
- }
ServerWindow.java
- packagecom.android.socket.server;
- importjava.awt.BorderLayout;
- importjava.awt.Frame;
- importjava.awt.Label;
- importjava.awt.event.WindowEvent;
- importjava.awt.event.WindowListener;
- publicclassServerWindowextendsFrame{
- privateSocketServerserver;
- privateLabellabel;
- publicServerWindow(Stringtitle){
- super(title);
- server=newSocketServer(8787);
- label=newLabel();
- add(label,BorderLayout.PAGE_START);
- label.setText("服务器已经启动www.linuxidc.com");
- this.addWindowListener(newWindowListener(){
- @Override
- publicvoidwindowOpened(WindowEvente){
- newThread(newRunnable(){
- @Override
- publicvoidrun(){
- try{
- server.start();
- }catch(Exceptione){
- e.printStackTrace();
- }
- }
- }).start();
- }
- @Override
- publicvoidwindowIconified(WindowEvente){
- }
- @Override
- publicvoidwindowDeiconified(WindowEvente){
- }
- @Override
- publicvoidwindowDeactivated(WindowEvente){
- }
- @Override
- publicvoidwindowClosing(WindowEvente){
- server.quit();
- System.exit(0);
- }
- @Override
- publicvoidwindowClosed(WindowEvente){
- }
- @Override
- publicvoidwindowActivated(WindowEvente){
- }
- });
- }
- /**
- *@paramargs
- */
- publicstaticvoidmain(String[]args){
- ServerWindowwindow=newServerWindow("文件上传服务端");
- window.setSize(300,300);
- window.setVisible(true);
- }
- }
- packagecom.android.socket.utils;
- importjava.io.ByteArrayOutputStream;
- importjava.io.File;
- importjava.io.FileOutputStream;
- importjava.io.IOException;
- importjava.io.InputStream;
- importjava.io.PushbackInputStream;
- publicclassStreamTool{
- publicstaticvoidsave(Filefile,byte[]data)throwsException{
- FileOutputStreamoutStream=newFileOutputStream(file);
- outStream.write(data);
- outStream.close();
- }
- publicstaticStringreadLine(PushbackInputStreamin)throwsIOException{
- charbuf[]=newchar[128];
- introom=buf.length;
- intoffset=0;
- intc;
- loop:while(true){
- switch(c=in.read()){
- case-1:
- case'\n':
- breakloop;
- case'\r':
- intc2=in.read();
- if((c2!='\n')&&(c2!=-1))in.unread(c2);
- breakloop;
- default:
- if(--room<0){
- char[]lineBuffer=buf;
- buf=newchar[offset+128];
- room=buf.length-offset-1;
- System.arraycopy(lineBuffer,0,buf,0,offset);
- }
- buf[offset++]=(char)c;
- break;
- }
- }
- if((c==-1)&&(offset==0))returnnull;
- returnString.copyValueOf(buf,0,offset);
- }
- /**
- *读取流
- *@paraminStream
- *@return字节数组
- *@throwsException
- */
- publicstaticbyte[]readStream(InputStreaminStream)throwsException{
- ByteArrayOutputStreamoutSteam=newByteArrayOutputStream();
- byte[]buffer=newbyte[1024];
- intlen=-1;
- while((len=inStream.read(buffer))!=-1){
- outSteam.write(buffer,0,len);
- }
- outSteam.close();
- inStream.close();
- returnoutSteam.toByteArray();
- }
- }
布局文件layout/main.xml
- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/filename"
- />
- <EditText
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="WinRAR_3.90_SC.exe"
- android:id="@+id/filename"
- />
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/button"
- android:id="@+id/button"
- />
- <ProgressBar
- android:layout_width="fill_parent"
- android:layout_height="20px"
- style="?android:attr/progressBarStyleHorizontal"
- android:id="@+id/uploadbar"
- />
- <TextView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:id="@+id/result"
- />
- </LinearLayout>
- <?xmlversion="1.0"encoding="utf-8"?>
- <resources>
- <stringname="hello">HelloWorld,UploadActivity!</string>
- <stringname="app_name">大视频文件断点上传</string>
- <stringname="filename">文件名称</string>
- <stringname="button">上传</string>
- <stringname="sdcarderror">SDCard不存在或者写保护</string>
- <stringname="success">上传完成</string>
- <stringname="error">上传失败</string>
- <stringname="filenotexsit">文件不存在</string>
- </resources>
- <?xmlversion="1.0"encoding="utf-8"?>
- <manifestxmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.upload"
- android:versionCode="1"
- android:versionName="1.0">
- <uses-sdkandroid:minSdkVersion="8"/>
- <application
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name">
- <activity
- android:name=".UploadActivity"
- android:label="@string/app_name">
- <intent-filter>
- <actionandroid:name="android.intent.action.MAIN"/>
- <categoryandroid:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- </application>
- <!--访问网络的权限-->
- <uses-permissionandroid:name="android.permission.INTERNET"/>
- <!--在SDCard中创建与删除文件权限-->
- <uses-permissionandroid:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
- <!--往SDCard写入数据权限-->
- <uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- </manifest>
- packagecom.android.upload;
- importjava.io.File;
- importjava.io.OutputStream;
- importjava.io.PushbackInputStream;
- importjava.io.RandomAccessFile;
- importjava.net.Socket;
- importandroid.app.Activity;
- importandroid.os.Bundle;
- importandroid.os.Environment;
- importandroid.os.Handler;
- importandroid.os.Message;
- importandroid.view.View;
- importandroid.widget.Button;
- importandroid.widget.EditText;
- importandroid.widget.ProgressBar;
- importandroid.widget.TextView;
- importandroid.widget.Toast;
- importcom.android.service.UploadLogService;
- importcom.android.utils.StreamTool;
- publicclassUploadActivityextendsActivity{
- privateEditTextfilenameText;
- privateTextViewresulView;
- privateProgressBaruploadbar;
- privateUploadLogServicelogService;
- privateHandlerhandler=newHandler(){
- @Override
- publicvoidhandleMessage(Messagemsg){
- intlength=msg.getData().getInt("size");
- uploadbar.setProgress(length);
- floatnum=(float)uploadbar.getProgress()/(float)uploadbar.getMax();
- intresult=(int)(num*100);
- resulView.setText(result+"%");
- if(uploadbar.getProgress()==uploadbar.getMax()){
- Toast.makeText(UploadActivity.this,R.string.success,1).show();
- }
- }
- };
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- logService=newUploadLogService(this);
- filenameText=(EditText)this.findViewById(R.id.filename);
- uploadbar=(ProgressBar)this.findViewById(R.id.uploadbar);
- resulView=(TextView)this.findViewById(R.id.result);
- Buttonbutton=(Button)this.findViewById(R.id.button);
- button.setOnClickListener(newView.OnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- Stringfilename=filenameText.getText().toString();
- if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
- FileuploadFile=newFile(Environment.getExternalStorageDirectory(),filename);
- if(uploadFile.exists()){
- uploadFile(uploadFile);
- }else{
- Toast.makeText(UploadActivity.this,R.string.filenotexsit,1).show();
- }
- }else{
- Toast.makeText(UploadActivity.this,R.string.sdcarderror,1).show();
- }
- }
- });
- }
- /**
- *上传文件
- *@paramuploadFile
- */
- privatevoiduploadFile(finalFileuploadFile){
- newThread(newRunnable(){
- @Override
- publicvoidrun(){
- try{
- uploadbar.setMax((int)uploadFile.length());
- Stringsouceid=logService.getBindId(uploadFile);
- Stringhead="Content-Length="+uploadFile.length()+";filename="+uploadFile.getName()+";sourceid="+
- (souceid==null?"":souceid)+"\r\n";
- Socketsocket=newSocket("192.168.1.123",8787);
- OutputStreamoutStream=socket.getOutputStream();
- outStream.write(head.getBytes());
- PushbackInputStreaminStream=newPushbackInputStream(socket.getInputStream());
- Stringresponse=StreamTool.readLine(inStream);
- String[]items=response.split(";");
- Stringresponseid=items[0].substring(items[0].indexOf("=")+1);
- Stringposition=items[1].substring(items[1].indexOf("=")+1);
- if(souceid==null){//代表原来没有上传过此文件,往数据库添加一条绑定记录
- logService.save(responseid,uploadFile);
- }
- RandomAccessFilefileOutStream=newRandomAccessFile(uploadFile,"r");
- fileOutStream.seek(Integer.valueOf(position));
- byte[]buffer=newbyte[1024];
- intlen=-1;
- intlength=Integer.valueOf(position);
- while((len=fileOutStream.read(buffer))!=-1){
- outStream.write(buffer,0,len);
- length+=len;
- Messagemsg=newMessage();
- msg.getData().putInt("size",length);
- handler.sendMessage(msg);
- }
- fileOutStream.close();
- outStream.close();
- inStream.close();
- socket.close();
- if(length==uploadFile.length())logService.delete(uploadFile);
- }catch(Exceptione){
- e.printStackTrace();
- }
- }
- }).start();
- }
- }
- packagecom.android.service;
- importjava.io.File;
- importandroid.content.Context;
- importandroid.database.Cursor;
- importandroid.database.sqlite.SQLiteDatabase;
- publicclassUploadLogService{
- privateDBOpenHelperdbOpenHelper;
- publicUploadLogService(Contextcontext){
- this.dbOpenHelper=newDBOpenHelper(context);
- }
- publicvoidsave(Stringsourceid,FileuploadFile){
- SQLiteDatabasedb=dbOpenHelper.getWritableDatabase();
- db.execSQL("insertintouploadlog(uploadfilepath,sourceid)values(?,?)",
- newObject[]{uploadFile.getAbsolutePath(),sourceid});
- }
- publicvoiddelete(FileuploadFile){
- SQLiteDatabasedb=dbOpenHelper.getWritableDatabase();
- db.execSQL("deletefromuploadlogwhereuploadfilepath=?",newObject[]{uploadFile.getAbsolutePath()});
- }
- publicStringgetBindId(FileuploadFile){
- SQLiteDatabasedb=dbOpenHelper.getReadableDatabase();
- Cursorcursor=db.rawQuery("selectsourceidfromuploadlogwhereuploadfilepath=?",
- newString[]{uploadFile.getAbsolutePath()});
- if(cursor.moveToFirst()){
- returncursor.getString(0);
- }
- returnnull;
- }
- }
- packagecom.android.service;
- importandroid.content.Context;
- importandroid.database.sqlite.SQLiteDatabase;
- importandroid.database.sqlite.SQLiteOpenHelper;
- publicclassDBOpenHelperextendsSQLiteOpenHelper{
- publicDBOpenHelper(Contextcontext){
- super(context,"upload.db",null,1);
- }
- @Override
- publicvoidonCreate(SQLiteDatabasedb){
- db.execSQL("CREATETABLEuploadlog(_idintegerprimarykeyautoincrement,uploadfilepathvarchar(100),sourceidvarchar(10))");
- }
- @Override
- publicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion){
- db.execSQL("DROPTABLEIFEXISTSuploadlog");
- onCreate(db);
- }
- }
相关推荐
使用java 语言实现的 Socket文件断点续传 ,可用于Android开发。
Android应用源码之Android中Socket大文件断点上传.zip项目安卓应用源码下载Android应用源码之Android中Socket大文件断点上传.zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 2.适合个人学习研究参考 3.适合...
Android应用源码开发Demo,主要用于毕业设计学习。
所谓Socket通常也称作“套接字”,用于描述IP地址和端口,是一个通信连的句柄,应用程序通常通过“套接字”向网络发送请求或者应答网络请求,它就是网络通信过程中端点的抽象表示。它主要包括以下两个协议: TCP ...
32_文件断点上传器.avi 所在项目:videoUpload & javaSE应用:socket 33_为应用添加多个Activity与参数传递.avi 所在项目:MulActivity 34_Activity的启动模式.avi 所在项目:LaunchMode & openSingleInstance & ...
32_文件断点上传器.avi 所在项目:videoUpload & javaSE应用:socket 33_为应用添加多个Activity与参数传递.avi 所在项目:MulActivity 34_Activity的启动模式.avi 所在项目:LaunchMode & openSingleInstance & ...
一个目标文件,演示Socket的使用。 Java 组播组中发送和接受数据实例 3个目标文件。 Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java...
32_文件断点上传器.avi 所在项目:videoUpload & javaSE应用:socket 33_为应用添加多个Activity与参数传递.avi 所在项目:MulActivity 34_Activity的启动模式.avi 所在项目:LaunchMode & openSingleInstance & ...
Java局域网通信——飞鸽传书源代码 28个目标文件 内容索引:JAVA源码,媒体网络,飞鸽传书 Java局域网通信——飞鸽传书源代码,大家都知道VB版、VC版还有Delphi版的飞鸽传书软件,但是Java版的确实不多,因此这个Java...