Android HttpConnection 文件上传
使用 HttpConnection
上传文件有点复杂,一般情况下都是用第三方库,不过,我们还是要实现一把,这样就更容易理解第三方库的某些设定
服务器端
如果使用 Servlet
开发一个服务器端比较复杂,我就直接用 GoLang
语言了
upserv.go
package main import ( "fmt" "io" "log" "net" "net/http" "os" "time" ) func indexHandle(w http.ResponseWriter, r *http.Request) { defer func() { if err := recover(); err != nil { fmt.Println("获取页面失败") } }() // 上传页面 w.Header().Add("Content-Type", "text/html") w.WriteHeader(200) html := `<!DOCTYPE html><meta charset="utf-8" /> <form id="uploadForm" enctype="multipart/form-data" action="/upload" method="POST"> <input type="file" id="file1" name="userfile" multiple /><input type="submit" value="上传"> </form>` io.WriteString(w, html) } func UploadServer(w http.ResponseWriter, r *http.Request) { defer func() { if err := recover(); err != nil { fmt.Println("文件上传异常") } }() if "POST" == r.Method { r.ParseMultipartForm(32 << 20) if r.MultipartForm != nil && r.MultipartForm.File != nil { fhs := r.MultipartForm.File["userfile"] //获取所有上传文件信息 num := len(fhs) fmt.Printf("总文件数:%d 个文件", num) //循环对每个文件进行处理 for n, fheader := range fhs { //获取文件名 filename := fheader.Filename //结束文件 file, err := fheader.Open() if err != nil { fmt.Println(err) } //保存文件 defer file.Close() f, err := os.Create(filename) defer f.Close() io.Copy(f, file) //获取文件状态信息 fstat, _ := f.Stat() //打印接收信息 fmt.Fprintf(w, "%s NO.: %d Size: %d KB Name:%s\n", time.Now().Format("2006-01-02 15:04:05"), n, fstat.Size()/1024, filename) fmt.Printf("%s NO.: %d Size: %d KB Name:%s\n", time.Now().Format("2006-01-02 15:04:05"), n, fstat.Size()/1024, filename) } } return } else { indexHandle(w, r) } } func main() { addrs, err := net.InterfaceAddrs() if err != nil { os.Stderr.WriteString("Oops:" + err.Error()) os.Exit(1) } for _, a := range addrs { if ipnet, ok := a.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { if ipnet.IP.To4() != nil { os.Stdout.WriteString(ipnet.IP.String() + "\n") } } } fmt.Println("Listening Port: 9999") http.HandleFunc("/", indexHandle) http.HandleFunc("/upload", UploadServer) err = http.ListenAndServe(":9999", nil) if err != nil { log.Fatal("ListenAndServe: ", err) } }
把上面的代码保存为 upserv.go
然后打开终端或命令行提示符,输入以下命令直接运行
go serv.go
或者你可以下载我已经编译好的文件 /static/i/android/upserv.zip 里面有两个文件 upserv_macox
为苹果电脑下运行的,upserv_win
为 Windows
下运行的 ,打开终端或命令行提示符,输入以下命令直接运行
upserv.exe
成功运行后会输出以下提示
221.221.221.221 192.168.0.108 Listening Port: 9999
内网地址就是以 192.168
开头的,这时候你可以通过内网地址访问服务,比如我的 http://192.168.0.108:9999/ 运行
客户端
-
创建一个 空的 Android 项目
cn.twle.android.HTTPUploadFile
-
在
app
上点击右键,选择Folder - Assets Folder
创建一个assets
目录 -
下载 /static/i/meimei.jpg 并且放到
assets
目录 -
修改
AndroidManifest.xml
中添加权限<!-- 往SDCard写入数据权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- 访问internet权限 --> <uses-permission android:name="android.permission.INTERNET"/>
-
修改
activity_main.xml
创建布局<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:padding="16dp"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="文件名" android:textSize="18sp" /> <EditText android:id="@+id/edit_fname" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="meimei.jpg" /> <Button android:id="@+id/btn_upload" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="上传" /> <TextView android:id="@+id/txt_result" android:padding="16dp" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center" /> </LinearLayout>
-
创建一个上传帮助类
UploadHelper.java
package cn.twle.android.httpuploadfile; import android.content.Context; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; public class UploadHelper { public static Boolean upload(Context context, String[] uploadFiles, String remote_url) { String end = "\r\n"; String twoHyphens = "--"; String boundary = "4e7050f8f4615005b4cd"; try { URL url = new URL(remote_url); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // 发送POST请求必须设置如下两行 conn.setDoInput(true); conn.setDoOutput(true); conn.setUseCaches(false); conn.setRequestMethod("POST"); conn.setRequestProperty("Connection", "Keep-Alive"); conn.setRequestProperty("Charset", "UTF-8"); conn.setRequestProperty("Content-Type","multipart/form-data;boundary=" + boundary); DataOutputStream ds = new DataOutputStream(conn.getOutputStream()); for (int i = 0; i < uploadFiles.length; i++) { String uploadFile = uploadFiles[i]; File f = new File(uploadFile); String filename = f.getName(); ds.writeBytes(twoHyphens + boundary + end); ds.writeBytes("Content-Disposition: form-data; name=\"userfile\" ;filename=\"" + filename + "\"" + end); ds.writeBytes(end); FileInputStream fStream = new FileInputStream(uploadFile); int bufferSize = 1024; byte[] buffer = new byte[bufferSize]; int length = -1; while ((length = fStream.read(buffer)) != -1) { ds.write(buffer, 0, length); } ds.writeBytes(end); fStream.close(); } ds.writeBytes(twoHyphens + boundary + twoHyphens + end); ds.flush(); ds.close(); ((MainActivity)context).sendMessage("数据发送完毕,正在等待服务器返回\n"); StringBuilder sb = new StringBuilder(); ByteArrayOutputStream message = new ByteArrayOutputStream(); byte buffer[] = new byte[1024]; int len = 0; if ( conn.getResponseCode() == 200 ) { InputStream is = conn.getInputStream(); String mes = conn.getResponseMessage(); String heander = conn.getHeaderFields().toString(); while ( (len = is.read(buffer) ) != -1) { message.write(buffer,0,len); } sb.append(new String(message.toByteArray())); ((MainActivity) context).sendMessage(sb.toString() + "\n"); message.close(); is.close(); } else { ((MainActivity)context).sendMessage("服务器返回状态:" + conn.getResponseCode()); } conn.disconnect(); } catch (Exception e) { ((MainActivity)context).sendMessage(e.getMessage() + "\n"); } return true; } }
-
修改
MainActivity.java
package cn.twle.android.httpuploadfile; import android.content.Context; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private EditText edit_fname; private Button btn_upload; private TextView txt_result; private StringBuilder sb; private String remote_url = "http://192.168.0.105:9999/upload"; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { txt_result.setText(sb.toString()); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sb = new StringBuilder(); // 把 assets 下的 python.chm 拷贝到 sd File root = Environment.getExternalStorageDirectory(); File dir = new File(root.getPath() + "/assets"); if ( !dir.exists()) { Boolean ok = dir.mkdirs(); } String modelFilePath = "meimei.jpg"; Assets2Sd(this, modelFilePath, dir.getPath() ); edit_fname = (EditText) findViewById(R.id.edit_fname); btn_upload = (Button) findViewById(R.id.btn_upload); txt_result = (TextView) findViewById(R.id.txt_result); btn_upload.setOnClickListener(this); } @Override public void onClick(View v) { final String filename = edit_fname.getText().toString(); if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { final File file = new File(Environment.getExternalStorageDirectory().getPath() + "/assets/",filename); if (file.exists()) { new Thread(new Runnable() { @Override public void run() { sendMessage("开始上传文件:" + file.getAbsolutePath() + "\n"); UploadHelper.upload(MainActivity.this,new String[] {file.getAbsolutePath()},remote_url); } }).start(); } else { sendMessage("文件并不存在~\n"); } } else { sendMessage("SD卡不存在或者不可用\n"); } } public void sendMessage(String msg) { sb.append(msg); handler.sendEmptyMessage(0x1001); } /*** * 调用方式 * * String path = Environment.getExternalStorageDirectory().toString() + "/" + "Tianchaoxiong/useso"; String modelFilePath = "Model/seeta_fa_v1.1.bin"; Assets2Sd(this, modelFilePath, path + "/" + modelFilePath); * * @param context * @param fileAssetPath assets中的目录 * @param SdPath 要复制到sd卡中的目录 */ public static void Assets2Sd(Context context, String fileAssetPath, String SdPath){ //测试把文件直接复制到sd卡中 fileSdPath完整路径 String dstFile = SdPath + "/" + fileAssetPath; File file = new File(dstFile); if (!file.exists()) { try { InputStream myInput; OutputStream myOutput = new FileOutputStream(dstFile); myInput = context.getAssets().open(fileAssetPath); byte[] buffer = new byte[1024]; int length = myInput.read(buffer); while(length > 0) { myOutput.write(buffer, 0, length); length = myInput.read(buffer); } myOutput.flush(); myInput.close(); myOutput.close(); } catch (IOException e) { e.printStackTrace(); } } else { } } }