原理
Android客户端模拟一个HTTP的Post请求到服务器端,服务器端接收相应的Post请求后,返回响应信息给给客户端。
PHP服务器
Android客户端
packagecom.example.uploadfile.app;importandroid.app.Activity;importandroid.os.Bundle;importandroid.os.Environment;importandroid.os.StrictMode;importandroid.view.View;importandroid.widget.Button;importandroid.widget.TextView;importandroid.widget.Toast;importjava.io.DataOutputStream;importjava.io.FileInputStream;importjava.io.InputStream;importjava.net.HttpURLConnection;importjava.net.URL;public class MainActivity extendsActivity
{private String fileName = "image.jpg"; //报文中的文件名参数
private String path = Environment.getExternalStorageDirectory().getPath(); //Don't use "/sdcard/" here
private String uploadFile = path + "/" + fileName; //待上传的文件路径
private String postUrl = "http://mycloudnote.sinaapp.com/upload.php"; //处理POST请求的页面
privateTextView mText1;privateTextView mText2;privateButton mButton;
@Overridepublic voidonCreate(Bundle savedInstanceState)
{super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);//"文件路径:\n"+
mText1 =(TextView) findViewById(R.id.myText1);
mText1.setText(uploadFile);//"上传网址:\n"+
mText2 =(TextView) findViewById(R.id.myText2);
mText2.setText(postUrl);/*设置mButton的onClick事件处理*/mButton=(Button) findViewById(R.id.myButton);
mButton.setOnClickListener(newView.OnClickListener()
{public voidonClick(View v)
{
uploadFile();
}
});
}/*上传文件至Server的方法*/
private voiduploadFile()
{
String end= "\r\n";
String twoHyphens= "--";
String boundary= "*****";try{
URL url= newURL(postUrl);
HttpURLConnection con=(HttpURLConnection) url.openConnection();/*Output to the connection. Default is false,
set to true because post method must write something to the connection*/con.setDoOutput(true);/*Read from the connection. Default is true.*/con.setDoInput(true);/*Post cannot use caches*/con.setUseCaches(false);/*Set the post method. Default is GET*/con.setRequestMethod("POST");/*设置请求属性*/con.setRequestProperty("Connection", "Keep-Alive");
con.setRequestProperty("Charset", "UTF-8");
con.setRequestProperty("Content-Type", "multipart/form-data;boundary=" +boundary);/*设置StrictMode 否则HTTPURLConnection连接失败,因为这是在主进程中进行网络连接*/StrictMode.setThreadPolicy(newStrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());/*设置DataOutputStream,getOutputStream中默认调用connect()*/DataOutputStream ds= new DataOutputStream(con.getOutputStream()); //output to the connection
ds.writeBytes(twoHyphens + boundary +end);
ds.writeBytes("Content-Disposition: form-data; " +
"name=\"file\";filename=\"" +fileName+ "\"" +end);
ds.writeBytes(end);/*取得文件的FileInputStream*/FileInputStream fStream= newFileInputStream(uploadFile);/*设置每次写入8192bytes*/
int bufferSize = 8192;byte[] buffer = new byte[bufferSize]; //8k
int length = -1;/*从文件读取数据至缓冲区*/
while ((length = fStream.read(buffer)) != -1)
{/*将资料写入DataOutputStream中*/ds.write(buffer,0, length);
}
ds.writeBytes(end);
ds.writeBytes(twoHyphens+ boundary + twoHyphens +end);/*关闭流,写入的东西自动生成Http正文*/fStream.close();/*关闭DataOutputStream*/ds.close();/*从返回的输入流读取响应信息*/InputStream is= con.getInputStream(); //input from the connection 正式建立HTTP连接
intch;
StringBuffer b= newStringBuffer();while ((ch = is.read()) != -1)
{
b.append((char) ch);
}/*显示网页响应内容*/Toast.makeText(MainActivity.this, b.toString().trim(), Toast.LENGTH_SHORT).show();//Post成功
} catch(Exception e)
{/*显示异常信息*/Toast.makeText(MainActivity.this, "Fail:" + e, Toast.LENGTH_SHORT).show();//Post失败
}
}
}
设置连接(HTTP头) -> 建立TCP连接 -> 设置HTTP正文 -> 建立HTTP连接(正式Post)-> 从返回的输入流读取响应信息
1.设置连接(HTTP头)
URL url = newURL(postUrl);
HttpURLConnection con=(HttpURLConnection) url.openConnection();/*Output to the connection. Default is false,
set to true because post method must write something to the connection*/con.setDoOutput(true);/*Read from the connection. Default is true.*/con.setDoInput(true);/*Post cannot use caches*/con.setUseCaches(false);/*Set the post method. Default is GET*/con.setRequestMethod("POST");/*设置请求属性*/con.setRequestProperty("Connection", "Keep-Alive");
con.setRequestProperty("Charset", "UTF-8");
con.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
2.建立TCP连接
DataOutputStream ds = new DataOutputStream(con.getOutputStream()); //output to the connection
con.getOutputStream()中会默认调用con.connect(),此时客户端与服务器建立的只是1个TCP连接而非HTTP。
HTTP请求=HTTP头+HTTP正文。
在connect()里面,会根据HttpURLConnection对象的配置值生成HTTP头,所以对con的一切配置都必须在connect()方法之前完成。
3.设置HTTP正文
正文通过DataOutputStream写入,只是写入内存而不会发送到网络中去,而是在流关闭时,根据写入的内容生成HTTP正文。
ds.writeBytes(twoHyphens + boundary +end);
ds.writeBytes("Content-Disposition: form-data; " +
"name=\"file\";filename=\"" +fileName+ "\"" +end);
ds.writeBytes(end);/*取得文件的FileInputStream*/FileInputStream fStream= newFileInputStream(uploadFile);/*设置每次写入8192bytes*/
int bufferSize = 8192;byte[] buffer = new byte[bufferSize]; //8k
int length = -1;/*从文件读取数据至缓冲区*/
while ((length = fStream.read(buffer)) != -1)
{/*将资料写入DataOutputStream中*/ds.write(buffer,0, length);
}
ds.writeBytes(end);
ds.writeBytes(twoHyphens+ boundary + twoHyphens +end);/*关闭流,写入的东西自动生成Http正文*/fStream.close();/*关闭DataOutputStream*/ds.close();
4.建立HTTP连接(正式Post)
至此,HTTP请求设置完毕,con.getInputStream()中会将请求(HTTP头+HTTP正文)发送到服务器,并返回一个输入流。所以在getInputStream()之前,HTTP正文部分一定要先设置好。
InputStream is = con.getInputStream(); //input from the connection 正式建立HTTP连接
5.从返回的输入流读取响应信息
intch;
StringBuffer b= newStringBuffer();while ((ch = is.read()) != -1)
{
b.append((char) ch);
}/*显示网页响应内容*/Toast.makeText(MainActivity.this, b.toString().trim(), Toast.LENGTH_SHORT).show();//Post成功
布局XML
两个Text和一个Button
View Code
AndroidManifest
添加网络权限、SD卡读写权限、挂载文件系统权限。
View Code
注意事项
1.由于Android不建议在主进程中进行网络访问,所以使用HttpURLConnection连接到服务端时抛出异常,加入以下语句即可。
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());
2.获取SD卡路径时,请使用Environment.getExternalStorageDirectory().getPath();而不是"/sdcard/"
另外几个个博客也很详细 :http://blog.csdn.net/caiwenfeng_for_23/article/details/47211745
http://www.jb51.net/article/77154.htm