原理

Android客户端模拟一个HTTP的Post请求到服务器端,服务器端接收相应的Post请求后,返回响应信息给给客户端。

PHP服务器

<?php 
  move_uploaded_file($_FILES['file']['tmp_name'], "./upload/".$_FILES["file"]["name"]);
?>

Android客户端

package com.example.uploadfile.app;

import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.StrictMode;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast; import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL; public class MainActivity extends Activity
{
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请求的页面
private TextView mText1;
private TextView mText2;
private Button mButton; @Override
public void onCreate(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(new View.OnClickListener()
{
public void onClick(View v)
{
uploadFile();
}
});
} /* 上传文件至Server的方法 */
private void uploadFile()
{
String end = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
try
{
URL url = new URL(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(new StrictMode.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 = new FileInputStream(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连接
int ch;
StringBuffer b = new StringBuffer();
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 = new URL(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 = new FileInputStream(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.从返回的输入流读取响应信息

int ch;
StringBuffer b = new StringBuffer();
while ((ch = is.read()) != -1)
{
  b.append((char) ch);
}
/* 显示网页响应内容 */
Toast.makeText(MainActivity.this, b.toString().trim(), Toast.LENGTH_SHORT).show();//Post成功

布局XML

两个Text和一个Button

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="${packageName}.${activityClass}"> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Text"
android:id="@+id/myText1"
android:layout_above="@+id/myText2"
android:layout_centerHorizontal="true"
android:layout_marginBottom="80dp"/> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Text"
android:id="@+id/myText2"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"/> <Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Upload"
android:id="@+id/myButton"
android:layout_marginTop="80dp"
android:layout_below="@+id/myText2"
android:layout_centerHorizontal="true"/>
</RelativeLayout>

AndroidManifest

添加网络权限、SD卡读写权限、挂载文件系统权限。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.uploadfile.app" > <application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.uploadfile.app.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
</manifest>

注意事项

1.由于Android不建议在主进程中进行网络访问,所以使用HttpURLConnection连接到服务端时抛出异常,加入以下语句即可。

StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());

2.获取SD卡路径时,请使用Environment.getExternalStorageDirectory().getPath();而不是"/sdcard/"

参考文章

HttpURLConnection学习

Android上传文件到Web服务器,PHP接收文件(一)

【Android开发那点破事】解决Andriod使用HttpURLConnection 失败问题

Android上传图片(PHP服务器)的更多相关文章

  1. Android 上传图片到服务器二--------调用相机7.0以上权限问题

    [目录] (一)上传图片到服务器一 ---------------------------------Android代码 (二)上传图片到服务器二--------------------------- ...

  2. Android 上传图片到服务器 okhttp一

    [目录] (一)上传图片到服务器一 ---------------------------------Android代码 (二)上传图片到服务器二--------------------------- ...

  3. Android上传图片到服务器

    一.android需要导入异步请求的jar包 AsyncHttpClient  public static void reg(final Context cont,Bitmap photodata,S ...

  4. android 上传图片到服务器Tomcat(Struts2)

    在做android开发的时候,有时你会用到图片的上传功能,在我的android项目中,我是选中图片,点击上传多张图片 android客户端上传图片部分的代码如下: package com.exampl ...

  5. android上传图片至服务器

    本实例实现了android上传手机图片至服务器,服务器进行保存 服务器servlet代码publicvoid doPost(HttpServletRequest request, HttpServle ...

  6. Android上传图片到服务器,服务端利用.NET WCFRest服务读取文件的解决方案

    在项目中遇到要将Android设备拍摄的照片上传的服务器,将文件保存在服务器本地的文件夹中,数据库中保存的是图片文件名.整个上传是将图片生成二进制流通过HTTP请求上传到服务端,服务端是基于.NET环 ...

  7. 通过android 客户端上传图片到服务器

    昨天,(在我的上一篇博客中)写了通过浏览器上传图片到服务器(php),今天将这个功能付诸实践.(还完善了服务端的代码) 不试不知道,原来通过android 向服务端发送图片还真是挺麻烦的一件事. 上传 ...

  8. Android客户端与服务器

    就是普通的服务器端编程,还不用写界面,其实还比服务器编程简单一些.跟J2EE一样的服务器,你android这一方面只要用json或者gson直接拿数据,后台的话用tomcat接受请求操作数据,功能不复 ...

  9. 【Android】与服务器实现JSON数据通信

    一.前言 作为一名移动端开发人员,具备一定的服务端开发能力也是非常必要的,本篇博客讲述如何在Android和服务器之间实现JSON数据通信交互,博客内容基于另外一篇博客:[Web]Eclipse + ...

  10. Wcf for wp8 上传图片到服务器,将图片名字插入数据库字段(五)

    环境:.NET Framework 3.5 服务: IIS EXpress托管 WCF服务程序 配置:Web.config <!--<connectionStrings> <a ...

随机推荐

  1. PHP安全:如何正确的取得使用者 IP?

    PHP安全:如何正确的取得使用者 IP? 很多网站都会有侦测用户 IP 的功能,不管是判断使用者来自哪边,或者是记录用户的位置.但是你知道吗?网络上大多数的教学全部都是「错误」的.正确的程序写法可以确 ...

  2. hdu 5311 Hidden String 字符串

    BC一周年的题.这道题做比赛的时候A了小数据,终于评判的时候还是挂了,看来还是不认真思考的问题啊.交的时候 都没有信心过肯定是不行的.认真思考.敲一发,有信心过才是真正的acmer.赛后认真想了想,发 ...

  3. Drupal的system_list()函数解析

    system_list()函数的目的是根据传入的资源类型,返回一个数组列表: function system_list($type) { ... ... } 参数$type支持下面三种类型: boot ...

  4. 常见SQL Server导入导出数据的几个工具

    摘自:http://www.cnblogs.com/chenxizhang/archive/2011/06/09/2076542.html 在我们的日常工作中,与数据库打交道的机会越来越多.这一篇文章 ...

  5. poj3177 Redundant Paths 边双连通分量

    给一个无向图,问至少加入多少条边能够使图变成双连通图(随意两点之间至少有两条不同的路(边不同)). 图中的双连通分量不用管,所以缩点之后建新的无向无环图. 这样,题目问题等效于,把新图中度数为1的点相 ...

  6. 转在Python中实现PageFactory模式

    转自: http://www.cnblogs.com/fnng/p/5092383.html 关于 PageFactory 的概念主要是Java中内置了PageFactory类. import org ...

  7. STL 容器(vector 和 list )

    1.这个容器的知识点比较杂 迭代器的理解: 1.erase()函数的返回值,它的迭代器在循环遍历中的奇特之处: #define _CRT_SECURE_NO_WARNINGS #include < ...

  8. Samba Server possible problem and solving

    Configured samba server at RHEL7, problem encountered and solved. 1, yum install samba*, RHEL7 syste ...

  9. Hive SQL 常见问题(转载)

    http://www.aboutyun.com/thread-14942-1-1.html 问题导读 1.Hive查询语句和SQL查询语句区别与联系. 2.distribute by.group by ...

  10. JSP中out.write()和out.print()的区别

    out对象的类型是JspWriter.JspWriter继承了java.io.Writer类. 1)print方法是子类JspWriter,write是Writer类中定义的方法: 2)重载的prin ...