安哥网络 发表于 2015-6-1 12:02:31

Android上传图片(PHP服务器)

Android上传图片(PHP服务器)
原理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;   //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 connectioncon.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;   //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服务器)
摘自:http://www.cnblogs.com/chenyg32/p/3822639.html

页: [1]
查看完整版本: Android上传图片(PHP服务器)