在项目中遇到要将Android设备拍摄的照片上传的服务器,将文件保存在服务器本地的文件夹中,数据库中保存的是图片文件名。整个上传是将图片生成二进制流通过HTTP请求上传到服务端,服务端是基于.NET环境的,采用ashx一般处理程序处理服务返回结果。
下面直接贴上代码,先是上传文件HTTP请求的静态方法:
1 /** 2 * 通过上传文件流形式上传文件 3 * @param picPaths 4 * @param requestURL 5 * @return 6 */ 7 public static String uploadFile(String[] picPaths, String requestURL) { 8 String boundary = UUID.randomUUID().toString(); 9 String prefix = "--", end = "\r\n"; 10 String content_type = "multipart/form-data"; // 内容类型 11 String CHARSET = "utf-8"; // 设置编码 12 int TIME_OUT = 10 * 10000000; // 超时时间 13 try { 14 URL url = new URL(requestURL); 15 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 16 conn.setReadTimeout(TIME_OUT); 17 conn.setConnectTimeout(TIME_OUT); 18 conn.setDoInput(true); // 允许输入流 19 conn.setDoOutput(true); // 允许输出流 20 conn.setUseCaches(false); // 不允许使用缓存 21 conn.setRequestMethod("POST"); // 请求方式 22 conn.setRequestProperty("Charset", "utf-8"); // 设置编码 23 conn.setRequestProperty("connection", "keep-alive"); 24 conn.setRequestProperty("Content-Type", content_type + ";boundary=" + boundary); 25 //当文件不为空,把文件包装并且上传 26 OutputStream outputSteam = conn.getOutputStream(); 27 DataOutputStream dos = new DataOutputStream(outputSteam); 28 29 StringBuffer stringBuffer = new StringBuffer(); 30 stringBuffer.append(prefix); 31 stringBuffer.append(boundary); 32 stringBuffer.append(end); 33 dos.write(stringBuffer.toString().getBytes()); 34 35 dos.writeBytes("Content-Disposition: form-data; name=\"" + author + "\"" + end); 36 dos.writeBytes(end); 37 dos.writeBytes("klose"); 38 dos.writeBytes(end); 39 40 for(int i = 0; i < picPaths.length; i++){ 41 File file = new File(picPaths[i]); 42 StringBuffer sb = new StringBuffer(); 43 sb.append(prefix); 44 sb.append(boundary); 45 sb.append(end); 46 sb.append("Content-Disposition: form-data; name=\"" + i + "\"; filename=\"" + file.getName() + end); 47 sb.append("Content-Type: application/octet-stream; charset=" + CHARSET + end); 48 sb.append(end); 49 dos.write(sb.toString().getBytes()); 50 51 InputStream is = new FileInputStream(file); 52 byte[] bytes = new byte[8192];//8k 53 int len = 0; 54 while ((len = is.read(bytes)) != -1) { 55 dos.write(bytes, 0, len); 56 } 57 is.close(); 58 dos.write(end.getBytes());//一个文件结束标志 59 } 60 byte[] end_data = (prefix + boundary + prefix + end).getBytes();//结束 http 流 61 dos.write(end_data); 62 dos.flush(); 63 64 //获取响应状态 65 int responseCode = conn.getResponseCode(); 66 67 if (HttpURLConnection.HTTP_OK == responseCode) { //连接成功 68 //当正确响应时处理数据 69 StringBuffer buffer = new StringBuffer(); 70 String readLine; 71 BufferedReader responseReader; 72 //处理响应流 73 responseReader = new BufferedReader(new InputStreamReader(conn.getInputStream())); 74 while ((readLine = responseReader.readLine()) != null) { 75 buffer.append(readLine).append("\n"); 76 } 77 responseReader.close(); 78 Log.d("HttpPOST", buffer.toString()); 79 return "保存成功!";//成功 80 } 81 }catch (Exception e) { 82 e.printStackTrace(); 83 } 84 return "保存失败!"; 85 }
二进制流报文格式如下所示:
1 --b8690cde-dc7b-48cb-868a-f328b6355a3c 2 Content-Disposition: form-data; name="author" 3 4 xxx 5 --b8690cde-dc7b-48cb-868a-f328b6355a3c 6 Content-Disposition: form-data; name="0"; filename="xxxx.jpg" 7 Content-Type: application/octet-stream; charset=utf-8 8 9 (这里是二进制数据) 10 --b8690cde-dc7b-48cb-868a-f328b6355a3c--
在.NET服务端接受二进制流的ashx程序代码如下所示:
1 /// <summary> 2 /// Handler1 的摘要说明 3 /// </summary> 4 public class Handler1 : IHttpHandler 5 { 6 string rootPath = ConfigurationManager.AppSettings["FileDirectory"]; 7 private IRepository _repository = new RepositoryImpl(); 8 9 public void ProcessRequest(HttpContext context) 10 { 11 12 var request = context.Request; 13 returnUploadResult(request); 14 15 } 16 17 public string returnUploadResult(HttpRequest request) 18 { 19 var files = request.Files; 20 var formUpload = request.Files.Count > 0; 21 22 string resultStr = ""; 23 24 if (formUpload) 25 { 26 27 for (int i = 0; i < request.Files.Count; i++) 28 { 29 var formFilename = formUpload ? request.Files[i].FileName : null; 30 var upload = new FineUpload 31 { 32 Filename = formFilename, 33 InputStream = formUpload ? request.Files[i].InputStream : request.InputStream 34 }; 35 string fileName = upload.Filename; 36 string fullFileName = Path.Combine(rootPath, fileName); 37 38 if (System.IO.File.Exists(fullFileName)) 39 { 40 XSBPHOTOURL template = new XSBPHOTOURL(); 41 template.NAME = fileName.ToString(); 42 template.IMGGUID = Guid.NewGuid().ToString(); 43 _repository.Save<XSBPHOTOURL>(template); 44 resultStr += (fullFileName + "已存在。 "); 45 } 46 else 47 { 48 XSBPHOTOURL template = new XSBPHOTOURL(); 49 template.NAME = fileName.ToString(); 50 template.IMGGUID = Guid.NewGuid().ToString(); 51 _repository.Save<XSBPHOTOURL>(template); 52 upload.SaveAs(fullFileName); 53 resultStr += (fullFileName + "保存成功。 "); 54 } 55 } 56 } 57 return resultStr; 58 59 } 60 61 public bool IsReusable 62 { 63 get 64 { 65 return false; 66 } 67 } 68 }
服务端文件保存路径写在WebConfig中,在appSettings中添加一行代码就可以了,示例如下:
<appSettings> <add key="FileDirectory" value="D:/UploadFiles"/> </appSettings>
这样就从Android客户端完成了文件上传功能,欢迎各位批评指正!