zoukankan      html  css  js  c++  java
  • 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);
            //"文件路径:
    "+
            mText1 = (TextView) findViewById(R.id.myText1);
            mText1.setText(uploadFile);
            //"上传网址:
    "+
            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 = "
    ";
            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失败
            }
        }
    }
    View Code

    设置连接(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>
    View Code

    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>
    View Code

    注意事项

    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 失败问题

  • 相关阅读:
    java的内存分配
    Java多线程sleep和wait的区别
    java static关键字
    在自己电脑创建svn服务、导入和导出项目
    开发工具下载地址
    svn操作步骤
    java的反射
    正数|非负数|正整数正小数和0 |金额正则表达式
    springBatch文件批处理
    IE浏览器问题之清除缓存!!!
  • 原文地址:https://www.cnblogs.com/chenyg32/p/3822639.html
Copyright © 2011-2022 走看看