博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android上传文件到PC的简单实例
阅读量:6766 次
发布时间:2019-06-26

本文共 15481 字,大约阅读时间需要 51 分钟。

hot3.png

      最近一直在完成个任务,有关Android手机文件传输的,现在先做了一步,实现了手机可以上传文件到pc端。

先简单介绍一下吧,架设在电脑上的pc端,运行在Android手机上的客户端,pc端用java语言编写,客户端这边是结合c和

java的JNI来编写的。为什么这么特殊呢~呵呵 ,完全是出于任务要求的需要啦!

      先上代码吧! 这边为了思路清晰点先上客户端的代码~顺序由上至下~

package zeng.Glogo.learn;import java.util.ArrayList;import java.util.List;import android.app.Activity;import android.app.ProgressDialog;import android.os.Bundle;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.AdapterView;import android.widget.AdapterView.OnItemSelectedListener;import android.widget.ArrayAdapter;import android.widget.Button;import android.widget.EditText;import android.widget.Spinner;import android.widget.Toast;public class JniClient_File extends Activity {	static{		System.loadLibrary("FileOperation");	}

 我自己建的包,还有需要的一些包~ static{}内的代码为用jni编写的静态库~

public String IPAddress="";	public int PORT;		private EditText editText1=null;	private EditText editText2=null;	private Spinner spinner=null;	private Button send=null;	private EditText editText3=null;	private EditText editText4=null;	private Button sure=null;	private Button connect=null;   //重点1	private Button disconnect=null; //重点2	private Button exit=null;	FileOperation fileOperation=new FileOperation();   //对文件进行操作的类 ,重点3	private ProgressDialog progressdialog;

这些都很简单吧~

private static final String file_Selected[]={		"选择您需要传输的文件","HelloJni.c","HelloNDK.c","HelloCDT.txt","HelloJava.java","Hello.txt","hellop.txt"	};	private static final String filePath[]={		" ","/mnt/sdcard/HelloJni.c","/mnt/sdcard/HelloNDK.c","/mnt/sdcard/HelloCDT.txt","/mnt/sdcard/HelloJava.java",		"/mnt/sdcard/Hello.txt","/mnt/sdcard/hellop.txt"	};	private ArrayAdapter
adapter; //声明一个适配器 private List
fileNamesList; //List容器,存放选择的文件名

有ArrayAdapter和List,大家应该才出来这些都是为Spinner做准备的吧~

/** Called when the activity is first created. */    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);          //根据控件的ID找到各个控件        editText1=(EditText)findViewById(R.id.file_name);        editText2=(EditText)findViewById(R.id.file_seletced);        spinner=(Spinner)findViewById(R.id.spinner);        send=(Button)findViewById(R.id.send);        editText3=(EditText)findViewById(R.id.ip);        editText4=(EditText)findViewById(R.id.port);        sure=(Button)findViewById(R.id.sure);        //progressbar=(ProgressBar)findViewById(R.id.progressBar);        connect=(Button)findViewById(R.id.connect);        disconnect=(Button)findViewById(R.id.disconnect);        exit=(Button)findViewById(R.id.exit);                //为容器List添加内容        fileNamesList=new ArrayList
(); for(int i=0;i
(this, android.R.layout.simple_spinner_item, file_Selected); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); //为Spinner添加适配器 spinner.setAdapter(adapter); //为Spinner添加时间监听 spinner.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView
arg0, View arg1, int arg2, long arg3) { // TODO Auto-generated method stub //arg2为点击所选择的选项 //arg0为spinner设置显示当前的选项 if(arg2!=0){ editText1.setText(filePath[arg2]); editText2.setText(file_Selected[arg2]); arg0.setVisibility(View.VISIBLE); }else{ editText1.setText(""); editText2.setText(""); editText1.setHint(R.string.file_name_hint); editText2.setHint(R.string.file_seletced_hint); arg0.setVisibility(View.VISIBLE); } } @Override public void onNothingSelected(AdapterView
arg0) { // TODO Auto-generated method stub //这个方法暂时不知道有什么用处,等待google之~ } });

 上面这些东东如果大家不了解的话去看一下有关Android入门的书,这些都会有的~

接下来的就是几个按钮的设定了~

 

//退出        exit.setOnClickListener(new OnClickListener() {			@Override			public void onClick(View v) {				// TODO Auto-generated method stub				JniClient_File.this.finish();			}		});        //确定IP和端口号        sure.setOnClickListener(new OnClickListener() {			@Override			public void onClick(View v) {				// TODO Auto-generated method stub				IPAddress=editText3.getText().toString();				PORT=Integer.decode(editText4.getText().toString());				editText3.setText("");				editText4.setText("");				editText3.setHint(IPAddress);				String port=String.valueOf(PORT);  //EditText的类型为Editable。接收String类型,所以在这里必须转换一下类型				editText4.setHint(port);				Toast toast=Toast.makeText(JniClient_File.this, 						"IP地址;"+IPAddress+"\n"+"端口号:"+PORT, Toast.LENGTH_LONG);				toast.show();			}		});                //建立连接        connect.setOnClickListener(new OnClickListener() {			@Override			public void onClick(View v) {				// TODO Auto-generated method stub				String str1=fileOperation.connect(IPAddress,PORT);				if(str1.endsWith("101")){					Toast toast=Toast.makeText(JniClient_File.this, str1+" 没有建立连接", Toast.LENGTH_LONG);					toast.show();				}				else{					Toast toast=Toast.makeText(JniClient_File.this, str1+" 连接已建立", Toast.LENGTH_LONG);					toast.show();				}			}		});        //断开连接        disconnect.setOnClickListener(new OnClickListener() {			@Override			public void onClick(View v) {				// TODO Auto-generated method stub				String str2=fileOperation.disconnect();				if(str2.endsWith("102")){					Toast toast=Toast.makeText(JniClient_File.this, str2+"  断开异常",Toast.LENGTH_LONG);					toast.show();				}else{					Toast toast=Toast.makeText(JniClient_File.this, str2+" 连接已断开", Toast.LENGTH_LONG);					toast.show();				}							}		});

 大家应该主要到了断开disconnect和 连接connect的功能都是调用我用jni编写的那个静态库(FileOperation)来实现的吧~并且还有相应的错误提示信息~接下来是最后一个按钮send~

 

send.setOnClickListener(new OnClickListener() {			@Override			public void onClick(View v) {				// TODO Auto-generated method stub				String str3=editText1.getText().toString();   //文件路径				String str4=editText2.getText().toString()+"\r\n";   //文件名				//String str4=editText2.getText().toString();				 int total=fileOperation.fileOperatin(str3,str4);				if(total<=0){					Toast toast=Toast.makeText(JniClient_File.this, "上传文件不成功"+total, Toast.LENGTH_LONG);					toast.show();				}				else{					Toast toast=Toast.makeText(JniClient_File.this, "the total is"+total, Toast.LENGTH_LONG);					toast.show();					progressdialog=new ProgressDialog(JniClient_File.this);					progressdialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);					progressdialog.setTitle("文件传输进度");					progressdialog.setMessage("~稍等一会哈~");					progressdialog.setIcon(R.drawable.android1);					progressdialog.setProgress(100);				    progressdialog.setIndeterminate(false);				    progressdialog.setCancelable(false);				    progressdialog.show();				    Log.d("DUBUG", "total is"+total);				    new Thread(){						int count=0;						public void run() {							// TODO Auto-generated method stub							try{								while(count<100)								{								progressdialog.setProgress(count+=4);								Thread.sleep(100);								}								progressdialog.cancel();							}catch(InterruptedException e){								e.printStackTrace();							}						}				    					    }.start();				}			}		});    }}

这个很简单吧~发送的东西交友jni编写的静待库去做了~它返回独到的字节数并Toast出来,这个便于我们统计嘛~还有一个progredialog。额·这个···美化一下哈~实际上没什么用处滴~

好了客户端java部分就到此为止了,下面是重头戏之一,FileOperation.so啦!!

继续上代码,大家如果对JNI有不熟悉的话可以先去了解一下哈~

 

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "zeng_Glogo_learn_FileOperation.h"#define MAXBUF 1024#define FILEPATH 255#define FILENAME 255int sockfd;unsigned char buffer[MAXBUF];char *end;unsigned char end_buf[29];struct sockaddr_in client_addr;jint Java_zeng_Glogo_learn_FileOperation_fileOperatin (JNIEnv *env, jobject thiz, jstring FilePath,jstring FileName){ const char *filepath_buf=(*env)->GetStringUTFChars(env,FilePath,0); char filepath[FILEPATH]; strcpy(filepath,filepath_buf); (*env)->ReleaseStringUTFChars(env,FilePath,filepath_buf); const char *filename_buf=(*env)->GetStringUTFChars(env,FileName,0); char filename[FILENAME]; memset(filename,0,FILENAME); strncpy(filename,filename_buf,strlen(filename_buf)); (*env)->ReleaseStringUTFChars(env,FileName,filename_buf); //开始读取文件,并发送给服务端 FILE *fp; fp=fopen(filepath,"rb"); if(!fp) { return -1; } int file_name=send(sockfd,filename,strlen(filename),0); //发送文件名 if(file_name<0) { return -2; } //int file_block_length=0; int count=0; //将文件分块传输 int ReadNum=0; int ReadSum=0; unsigned char LenBuffer[1]; while(!feof(fp)) //读取文件的内容到buffer中 { ReadNum=fread(buffer,1,MAXBUF,fp); ReadSum+=ReadNum; if(ReadNum>0) { if(send(sockfd,buffer,ReadNum,0)==-1) { fclose(fp); return -3; } bzero(buffer,MAXBUF); count++; } else { fclose(fp); break; } } //bzero(buffer,MAXBUF); /*end="EndLessLimiteFromGlogoPassion"; strcmp(end_buf,end); send(sockfd,end_buf,29,0);*/ //send(sockfd,end_buf,strlen(end_buf),0); fclose(fp); return ReadSum;}jstring Java_zeng_Glogo_learn_FileOperation_connect (JNIEnv *env, jobject thiz, jstring IPAddress, jint PORT){ //转换String类型 const char * ipaddress_buf=(*env)->GetStringUTFChars(env,IPAddress,0); char ipaddress[255]; strcpy(ipaddress,ipaddress_buf); (*env)->ReleaseStringUTFChars(env,IPAddress,ipaddress_buf); int port=PORT; bzero(&client_addr,sizeof(client_addr)); //把一段内存区的内容全部设置为0 /* AF_INET域 struct sockaddr_in { short int sin_family; //AF_INET unsigned short int sin_port; //Port number struct in_addr{ unsigned long s_addr //Internet address } }*/ sockfd=socket(AF_INET,SOCK_STREAM,0); if(sockfd<0) { return (*env)->NewStringUTF(env,"Socket Error 101"); } client_addr.sin_family=AF_INET; //internet协议族 client_addr.sin_port=htons(port); //端口号 /*也可以这么写 client_addr.sin_addr.s_addr=inet_addr(ipaddress); //转化IP地址 inet_addr和inet_aton的不同在于结果返回值的形式不同, //inet_addr返回值为in_addr_t, inet_aton返回值为整形,但两者的转换的地址仍存放在straddr中 //in_addr_t inet_addr(const char* straddr) , int inet_aton(const char* straddr,struct in_addr *addrp) //另外,sin_addr.s_addr=htonl(INADDR_ANY)表示*/ if(inet_aton(ipaddress,&client_addr.sin_addr)<0) { return (*env)->NewStringUTF(env,"inet_aton Error 101"); } if(connect(sockfd,(struct sockaddr*)&client_addr,sizeof(client_addr))<0) { return (*env)->NewStringUTF(env,"Connect Error 101"); } else { return (*env)->NewStringUTF(env,"Connec OK!"); } }jstring Java_zeng_Glogo_learn_FileOperation_disconnect (JNIEnv *env, jobject thiz){ close(sockfd); return (*env)->NewStringUTF(env,"Socket Close!");}

大家应该看到了~这些都是Linux下C编程的一些简单的东西,这里说明一下,在jint Java_zeng_Glogo_learn_FileOperation_fileOperatin函数中的count变量是没什么用的,我懒得删掉而已哈~

在发送文件这边没什么的,就是根据传进来的文件路径FilePath打开文件读取内容,并发送文件名给服务端,然后就是在!fp的情况下一次一次的send而已。嗯~客户端的就到此为止啦!!

下面的是服务端的啦~在这里我纠结了很久,后来终于发现问题,发送方发送的字节数是对的,但是接收方由于是java编写的,所以传过来的时候会涉及到基本数据类型的转换问题,这是一个老问题了~但是嘛~基础不够扎实的我还是忽略了~在这里耽误了很多时间,好了~上代码吧~!

 

package learn;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.DataInputStream;import java.io.File;import java.io.FileOutputStream;import java.io.FileWriter;import java.io.IOException;import java.io.InputStreamReader;import java.net.ServerSocket;import java.net.Socket;import java.nio.ByteBuffer;public class JniServer_File implements Runnable{		int PORT=8888;                	/**	 * @param args	 */	@Override	public void run() {		// TODO Auto-generated method stub		try{			System.out.println("      服务器开启...");			System.out.println("----  ----  ----  ----");			ServerSocket serverSocket=new ServerSocket(PORT);			while(true){				Socket client=serverSocket.accept();				System.out.println("      接收到客户端请求...");				System.out.println("----  ----  ----  ----");				System.out.println("      打开输入流。。");				System.out.println("----  ----  ----  ----");								BufferedInputStream filename=new BufferedInputStream(client.getInputStream());				System.out.println("      正在读取内容(文件名)...");				System.out.println("----  ----  ----  ----");				byte file_name[]=new byte[255];				filename.read(file_name);			    String file_name_trans=new String(file_name);				System.out.println("      读取文件名完毕,文件名是"+new String(file_name));								System.out.println("----  ----  ----  ----");				try{				if(file_name_trans!=""){					System.out.println("      开始创建文件.. "+file_name_trans);											String file="D:/Eclipse/test/HelloCDT.txt";        //文件的绝对路径										File newFile=new File(file);               //创建文件对象				      if(newFile.exists())				      {				    	  //检查文件在当前路径下是否存在					      newFile.createNewFile();  					  }									     					  System.out.println("----  ----  ----  ----");					 System.out.println("----  ----  ----  ----"); 					 					  System.out.println("       打开文件输出流,准备将读取内容写入相应文件");					   BufferedOutputStream file_context_in_buf=new BufferedOutputStream(new FileOutputStream(file,false));					  System.out.println("----  ----  ----  ----"); 					  System.out.println("       正在将内容写入文件...");					  					  int count=0;                          //测试用的标志					  byte[] file_context=new byte[1024];					  while(filename.read(file_context)>0){                     //循环读取文件内容,并写入到相应的文件保存起来						  count++;                           						  System.out.println("    read times for "+count);											  String end_buf_str=new String(file_context);						  if(end_buf_str.contains("END")){							  int len=end_buf_str.lastIndexOf("END");							  String end_buf_str1=end_buf_str.substring(0, len+3);							  byte end_buf_byte[]=end_buf_str1.getBytes();							  file_context_in_buf.write(end_buf_byte);							  System.out.println("    write times for "+count);							  System.out.println("    This times is "+count);							  System.out.println("----  ----  ----  ----"); 							  break;						  }						  						  file_context_in_buf.write(file_context);						  System.out.println("    write times for "+count);						  System.out.println("    This times is "+count);						  System.out.println("----  ----  ----  ----"); 					  }					  					  file_context_in_buf.flush();					  System.out.println("    file_context_in_buf flush times for "+count);					  System.out.println("----  ----  ----  ----"); 					  System.out.println("       写入完毕,请打开文件查看..."+count);					  System.out.println("----  ----  ----  ----"); 					  System.out.println("       关闭文件各种流...");					  System.out.println("----  ----  ----  ----"); 					  file_context_in_buf.close();         //先关闭外层的缓冲连接流					  filename.close();					  file_name_trans="";					  	  				 }								}				catch(IOException e){					e.printStackTrace();					System.out.println(e.getMessage()+" ---1");				}				finally{					client.close(); //关闭socket	                  System.out.println("     关闭连接");				}			}		}		catch(Exception e){			e.printStackTrace();				System.out.println(e.getMessage()+" ---2");			}		}				public static void main(String[] args) {		// TODO Auto-generated method stub		Thread jniServer_File=new Thread(new JniServer_File());		jniServer_File.start();	}}

熟悉java的同学应该清楚上面的代码吧~比较特殊的是在循环接收客户端send()过来的东西的时候,我这边做了一点小偷懒,就是发送是.txt文件最后都是以END结尾的,这个给了我一个方便,就是我可以根据这个来判断什么时候终止再往文件写入内容。还有一点是,传输是以字节为单位来传输的,所以要用Strean来接收和存入,用字符流Reader和Writer都是不靠谱的!这里面还涉及到String和byte类型的转化问题,我在这里也纠结过很久啦~呵呵 ,大家先别喷,我坦诚是我的基础部够扎实啦~

好了基本就是这样子的! 这边的上图比较麻烦,所以没图没真相···额好吧········大家这样想的话也么办法啦·不过本人已经试验过啦~一个15014KB的文件还有一个396800KB的文件传输都是没问题的,放在手机上测试也OK~

上图不方便我这里贴一下man.xml的代码让大家都整个布局都有些了解吧~

 

当然整个程序的bug还是很明显的~不过基本功能以及可以实现~不足之处亟待完善~希望大家多多指教~

第一次写博客哦~哈哈!

转载于:https://my.oschina.net/zjh92119/blog/60197

你可能感兴趣的文章