Android通過socket實現上傳大文件到服務器
上傳文件,我用了兩種方式實現,首先是用對象序列化,即把要上傳的數據打包成要上傳的對象,然后上傳。
需要注意的是:序列化的那兩個類一定要相同,包括包名。(其實就是客戶端和服務器端的javabean類,不過加上Serializable)
本人由于沒有處理好服務器端和客戶端的包名而使程序不能執行。
同時: 在客戶端進行序列化,在服務器端就進行反序列化。
好了,上代碼:
首先是序列化的類:
public class UploadFile implements Serializable {
private String title;
private byte[] contentdata;
private String mimetype;
private String type;
private long length;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public byte[] getContentdata() {
return contentdata;
}
public void setContentdata(byte[] contentdata) {
this.contentdata = contentdata;
}
public String getMimetype() {
return mimetype;
}
public void setMimetype(String mimetype) {
this.mimetype = mimetype;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public long getLength() {
return length;
}
public void setLength(long length) {
this.length = length;
}
}
public class MainSocket extends Activity {
private Button butchose=null;
private Button up=null;
private TextView text=null;
private static String filePath=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.mainsocket);
butchose=(Button)super.findViewById(R.id.socketchose);
text=(TextView)super.findViewById(R.id.socketshow);
up=(Button)super.findViewById(R.id.socketup);
butchose.setOnClickListener(new MyButton());
up.setOnClickListener(new MyButton());
}
//button按鈕的不同實現
class MyButton implements OnClickListener{
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.socketup://發送文件按鈕
try {
if(text.getText().toString()==null)
{ Toast.makeText(MainSocket.this, "請選擇上傳文件", 3).show();}
sendup();
} catch (Exception e) {
e.printStackTrace();
}
break;
default:
break;
}
}
}
//發送文件函數
public void sendup() throws Exception{
final Socket socket=new Socket("服務器ip",8897); //建立socket連接
BufferedReader buffer=new BufferedReader(new InputStreamReader(socket.getInputStream()));//構建一個緩沖區,用于存放服務器返回的數據
new Thread(new Runnable(){//開啟一個新線程,用于發送數據
@Override
public void run() {
try {
ObjectOutputStream obj=new ObjectOutputStream(socket.getOutputStream());//對象序列化的應用
UploadFile file=MainSocket.this.upfile();//從下面那個函數中得到序列化的對象
obj.writeObject(file);//把對象發送出去
} catch (IOException e) {
e.printStackTrace();
}
}}).start();
String s=buffer.readLine().toString();//得到服務器返回的數據
System.out.println("-------------------返回的數據是"+s);
if(s.equals("true")){
text.setText("操作成功!");
}
else{
text.setText("操作失敗");
}
socket.close();
}
//構造序列化對象
public UploadFile upfile(){
UploadFile upfile=new UploadFile();
upfile.setTitle("自行設置");
upfile.setMimetype("自行設置");
try {
File file=new File(filePath);//得到發送的文件
InputStream in=new FileInputStream(file) ;//打開文件的輸出流(前臺的輸入流)
ByteArrayOutputStream ous=new ByteArrayOutputStream();//聲明一個字節流
byte[] data=new byte[1024];//緩存數組
int len=0;
while((len=in.read(data))!=-1){//把前面輸入流的數據送到字節流中
ous.write(data,0,len);
}
upfile.setContentdata(ous.toByteArray());//把字節流的數據送到javabean中,即序列化對象中
upfile.setLength(file.length());//設置長度
upfile.setType(filePath.substring(filePath.lastIndexOf(".")+1));
} catch (Exception e) {
e.printStackTrace();
}
return upfile;
}
}
服務器端:
package lxf.com;
import java.io.IOException;
import java.net.ServerSocket;
public class server {
public static void main(String[] args) {
try {
ServerSocket socket=new ServerSocket(8897);
while(true){
new Thread(new ServerThread(socket.accept())).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
服務器端實現類:
package lxf.com;
import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.UUID;
import lxf.socket.UploadFile;
public class ServerThread implements Runnable {
private String PATH="d:"+File.separator+"lxf"+File.separator;
private UploadFile uploadfile=null;
private Socket socket;
public ServerThread(Socket socekt1){
this.socket=socekt1;
System.out.println("建立新的連接");
}
@Override
public void run() {
try {
ObjectInputStream input=new ObjectInputStream(socket.getInputStream());//進行反序列化
uploadfile=new UploadFile();
this.uploadfile=(UploadFile)input.readObject();//把流數據轉換成序列化對象
System.out.println("文件長短是:"+uploadfile.getLength());
System.out.println("文件格式:"+uploadfile.getType());
PrintStream out=new PrintStream(socket.getOutputStream());//建立socket輸出流
save();
out.println("true");//給客戶端應答
} catch (Exception e) {
e.printStackTrace();
}
finally{
}
}
public boolean save() throws Exception{
File file=new File(PATH+UUID.randomUUID()+"."+uploadfile.getType());//建立一個文件夾
if(!file.getParentFile().exists())//父文件不存在建立父文件
{
file.getParentFile().mkdir();
}
OutputStream output=new FileOutputStream(file);//打開控制臺輸出流
output.write(uploadfile.getContentdata());//把數據寫入文件
output.close();
return true ;
}
}
由于本人每一步寫的很細,標的也很細。大家應該可以看懂。
ObjectInputStream與ObjectOutputStream類所讀寫的對象必須實現了Seralizable接口。對象中的transient和static類型的成員變量不會被讀取和寫入。
另外,客戶端的布局大家可以自行設置。在這里,還有第二種方法:實現多線程多用戶斷點續傳功能,也是用數據流的方式上傳。