最近在做Android手机端的上传和下载功能。     上传文件的时候遇到了很大的麻烦,因为开始对网络编程这块十分不熟悉,加上对WEB服务器端也是一点不懂,搞了快一个星期才勉强实现,下面记录一下自己的过程:其中参考了网络编程的书籍,我本来是要对一个受保护的服务器进行上传文件,即需要输入帐号密码才可以成功上传文件,基于基础差,先做一个不用账户密码的,接下来再去实现可以访问受保护的服务器的功能。

1、首先搭建服务器端,朋友推荐我用了一款phpstudy集成的服务器环境搭建工具,确实非常好用。不用懂太多的PHP端,首先在phpstudy目录下的WWW目录下创建一个HTML文件,简单的写一个可以实现上传功能的界面,即一个选择文件框,还有一个上传的文件按钮,具体代码如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>无标题文档</title>
</head>

<body>
<span style="color:#ff0000;"><form action="upload_file.php" method="post" enctype="multipart/form-data">
<label for="file">文件名:</label>
<input type="file" name="file1" id="file" />
<br/>
<input type="submit" name="submit" value="提交" />
</form></span>
</body>
</html>



添加的代码就是图上标记为红色的部分,在<body>里边添加。说明一下,这个<form>标签用于为用户输入创建HTML表单。

<input type = "file"/>标签在被浏览器解析后会产生一个文本框和一个“浏览”按钮。单击浏览会弹出系统的文件选择框:如下图:


HTML中的form标签属性如下图:


图片来源与书上。

代码中的action=“upload_file.php”表示文件提交的时候会执行upload_file.php中的代码,这个文件主要实现对上传文件进行检查、复制等处理,代码如下:

创建一个PHP文件,也放在WWW目录下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>无标题文档</title>
</head>

<body>
<span style="color:#ff0000;"><?php
if($_FILES["file1"]["size"]<20000)               //文件大小控制在20000字节内,超出则不接受,这个可以自己改。
{
	if($_FILES["file1"]["error"]>0)           //上传文件的错误代码,如果返回了错位代码可以对照错误信息进行修正
	{
		echo "Return Code:".$_FILES["file1"]["error"]."<br />";
		
		
	}
	else
	{

	echo "Upload: ".$_FILES["file1"]["name"]."<br />";        //显示文件的名字,类型,大小,临时存放文件的路径
	echo "Type: ".$_FILES["file1"]["type"]."<br />";
	echo "Size: ".($_FILES["file1"]["size"]/1024)."kb<br />";
	echo "Temp file1:".$_FILES["file1"]["tmp_name"]."<br />";
	if(file_exists("./upload/".$_FILES["file1"]["name"]))        //检测文件是否存在于upload目录下(这个目录是用来存放上传文件的目录,也是建立<span style="white-space:pre">									</span>在WWW目录下的),如果存在则返回提示。
	{
		echo $_FILES["file1"]["name"]."already existst!";
	}
	else
	{</span>
<span style="color:#ff0000;"></span><pre name="code" class="php" style="color: rgb(255, 0, 0); ">//调用了一个PHP函数move_uploaded_file,把临时文件存放到我们制定的目录,并且改成我们上传时候的文件的名字。


move_uploaded_file($_FILES["file1"]["tmp_name"],"upload/".$_FILES["file1"]["name"]); 
 

 echo "Strore in:"."upload/".$_FILES["file1"]["name"]; //}}}else {echo "Invalid file1"; //文件超过20000字节则提示出错。}?></body></html>



还是红色代码为写的PHP代码。这个代码主要采用

$_FILES这个全局变量,这个 全局变量会获取上传文件的消息,并用此变量来进行操作,例如检查文件大小、位置、是否存在等。具体解释见以上代码。

至此我们的服务端的环境搭好了就,我们可以运行一下(首先在WWW目录下建立一个upload文件夹 这个也是跟上边的PHP里边的upload路径对应)。http://localhost/up.html  这个时候就会弹出选择文件上传的提示框,然后选文件上传就之后提示成功,就可以在WWW下的upload里查看上传文件,因为在php.ini配置文件中对上传文件大小做了控制,想要上传大文件的话可以在php.ini里边设置2个属性的大小:post_max_size          upload_max_filesize

把这两个属性设置好就可以了。

接下来就是安卓端代码的编写,这个代码也困扰了我好久,因为是看书上的例子,总也不能上传成功,后来发现是书上的列子传递参数好像传递错了,我改了一下就可以了。

代码如下:

首先是负责上传的工具类 httppost.java

package com.example.uploadfile;

import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.util.Log;

public class httppost {
	
	public static String post(String actionurl,String FileName) throws IOException  // 静态方法,直接在另外的类里可以调用
	{
		String BOUNDARY = java.util.UUID.randomUUID().toString();   //调用一个函数随机生成一个字符串作为分割线
		String PREFIX = "--",LINEND = "\r\n";
		String MULTIPART_FORM_DATA = "multipart/form-data";   //表单数据常量化
		String CHARSET = "UTF-8";  <span style="white-space:pre">				</span>//字符编码
		
		URL url = new URL(actionurl);                              
		HttpURLConnection conn = (HttpURLConnection)url.openConnection();//建立HTTP连接
		conn.setReadTimeout(5*1000);   <span style="white-space:pre">	</span>//设置从主机读取数据超时时间 单位:毫秒
		conn.setDoInput(true);<span style="white-space:pre">		</span>//设置允许输入
		conn.setDoOutput(true);<span style="white-space:pre">		</span>//设置允许输出
		conn.setUseCaches(false);<span style="white-space:pre">	</span>//设置不使用缓存
		conn.setRequestMethod("POST");   // 设置为POST发送方法
		conn.setRequestProperty("Connection", "Keep-Alive");//设置维持长连接
		conn.setRequestProperty("Charsert", "UTF-8");//设置文件字符集为UTF-8
		conn.setRequestProperty("Content-Type", MULTIPART_FORM_DATA                //设置文件类型
				  + ";boundary=" + BOUNDARY);
<span style="white-space:pre">		</span>//创建一个新的数据输出流,将数据写入指定的基础输出流
		DataOutputStream outstream = new DataOutputStream(conn.getOutputStream());
		if(FileName!="")   //发送文件数据
		{
<span style="white-space:pre">			</span>//定义StringBuilder对象构建发送字符串数据
			StringBuilder sb1 = new StringBuilder();
			sb1.append(PREFIX);
			sb1.append(BOUNDARY);
			sb1.append(LINEND);
			sb1.append("Content-Disposition: form-data;name=\"file1\"; filename=" + FileName + LINEND);
			sb1.append("Content-Type: application/octet-stream; charset="+ CHARSET + LINEND);
			sb1.append(LINEND);
			//写入输出流中
			outstream.write(sb1.toString().getBytes());
			//将文件读到输入流中
			InputStream is = new FileInputStream(FileName);
			byte[] buffer = new byte[1024];
			int len = 0;
<span style="white-space:pre">			</span>//写入输出流中<span style="white-space:pre">		</span>
			while((len=is.read(buffer))!=-1)
				
			{
				System.out.println(len);
				Log.v("len","keb");
				outstream.write(buffer,0,len);
			}
			is.close();//关闭输入流
<span style="white-space:pre">			</span>//添加换行标志
			outstream.write(LINEND.getBytes());
			
		}
		//请求结束标志
		byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINEND).getBytes();
outstream.write(end_data);
<span style="white-space:pre">		</span>//刷新,发送数据
		outstream.flush();
<span style="white-space:pre">		</span>//得到响应码
		int res = conn.getResponseCode();
		InputStream in = null;
<span style="white-space:pre">		</span>//上传成功返回相应码200
		if(res == 200)
		{
			Log.v("res","200");
			in = conn.getInputStream();
			int ch;
			StringBuilder sb2 = new StringBuilder();
			while((ch=in.read())!=-1)
			{
	
				sb2.append((char)ch);	
			}
			
		}
		return in==null?null:in.toString();
		
	}

}



代码具体解释看下注释吧,我出错的地方就是在 传递这句代码的时候出错的:sb1.append("Content-Disposition: form-data;name=\"file1\"; filename=" + FileName + LINEND);基于HTTP协议发送这个HTTP头,要有正确的格式,注意一下就好,要能够给filename一个正确的名字。这个filename是服务器端需要的参数,服务端通过这个参数值获得文件的名字。

接下来是Activity代码:

package com.example.uploadfile;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import com.example.filechooser.CallbackBundle;
import com.example.filechooser.OpenFileDialog;
import com.example.uploadfile.R;

import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.app.Dialog;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {


	public String url = "http://172.20.150.23/upload_file.php";
	public static Dialog dialog;
	public String uploadfilepath;
	public String uploadfilename;
	
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		Button btn =(Button)findViewById(R.id.btn1);
		
		btn.setOnClickListener(new OnClickListener(){

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				
				new Thread(runnable).start();
			}
			
		});
	}
	Runnable runnable = new Runnable()
	{
		public void run()
		{
			String filename = uploadfilepath;//uploadfilepath是自己指定的上传文件的路径和名字
			try {
				Log.v("path",filename);
				String res=httppost.post(url,filename);
				Log.v("httres",res);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				Log.v("tag","error!");
				e.printStackTrace();
			}
		}
		
	};
  
     }  
	
	
}



这个代码比较简单就是定义了一个按钮点击上传即可。