原理

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. 算法笔记_081:蓝桥杯练习 算法提高 矩阵乘法(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 问题描述 有n个矩阵,大小分别为a0*a1, a1*a2, a2*a3, ..., a[n-1]*a[n],现要将它们依次相乘,只能使用结合率,求最 ...

  2. 算法笔记_065:分治法求逆序对(Java)

    目录 1 问题描述 2 解决方案 2.1 蛮力法 2.2 分治法(归并排序)   1 问题描述 给定一个随机数数组,求取这个数组中的逆序对总个数.要求时间效率尽可能高. 那么,何为逆序对? 引用自百度 ...

  3. TP框架模板中默认值输出

    TP框架模板中默认值输出 我们可以给变量输出提供默认值,例如: {$user.nickname|default="这家伙很懒,什么也没留下"} 对系统变量依然可以支持默认值输出,例 ...

  4. 安卓Camera APP

    一.Camera package android.hardware            该类用于设定图像捕获设置,开启/关闭预览,抓拍图片以及获取帧用于编码视频.这个类是Camera服务的客户端,用 ...

  5. tar 命令详解 / xz 命令

    ]# tar [-cxtzjvfpPN] 文件与目录 ....参数:-c :建立一个压缩文件的参数指令(create 的意思):-x :解开一个压缩文件的参数指令!-t :查看 tarfile 里面的 ...

  6. mongodb进阶三之mongodb管理

    http://blog.csdn.net/stronglyh/article/details/46827141 平时的开发环境win比較多啊,但生产环境要放到unix环境上 一:命令 安装就不少了,网 ...

  7. 改动文件后缀的C语言实现

    ,其他配置项保持一致.         step 3: 在"Old2New"目录下新建名为"update.bat"的批处理文件,该文件的内容为: ChangeS ...

  8. lnmp1.4环境FTP服务器的安装和使用

    首先还是用Xshell连接到VPS界面,进入lnmp解压后的目录,命令如下: cd lnmp1.4     然后安装FTP服务器,命令如下: ./pureftpd.sh   看到提示Press any ...

  9. 用js来传参到父网页实现

    今天搞了半天,用location.href提交参数到后台,结果php无法接收到参数,这让我找了半天,终于发现原因是本页被另外的主页引用了,最终发现问题出在提交js上,最终用parent.locatio ...

  10. NIO - Selector源码分析

    1. 背景 SelectableChannel对象的多路复用器. 可以通过调用Selector.open()方法创建Selector对象.Selector.open()方法会利用系统默认的Select ...