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[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/"
参考文章Android上传图片(PHP服务器)
摘自:http://www.cnblogs.com/chenyg32/p/3822639.html
|