android存储之网络存储和数据库存储

原创 2015年07月09日 10:37:55

昨天说老师说了android的网络存储,对协议有了一个更深的理解。

数据上传到网络,尽管 b/s 和c/s的架构不一样,但是它们还是能上传数据到网络,因为都遵循协议的规范,c/s存储数据到网络,思想模仿浏览器发送数据服务器的请求头信息,在底层通过android提供的socket去链接网络,发送相应的数据,如果协议没拼接错误的话,能获得正确的相应码,并作出相应的操作。

总的来说,其实android网络存储重点还是对协议的拼接的,在此过程中必须静下心来才能做好拼接操作。

b/s通过访问服务器的网络段的请求头数据如下:·

<span style="white-space:pre">	<span style="font-size:14px;">	</span></span><span style="font-size:14px;">POST /ownUploadServer/doupload.action HTTP/1.1
		Host: localhost
		User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:35.0) Gecko/20100101 Firefox/35.0
		Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
		Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
		Accept-Encoding: gzip, deflate
		Referer: http://localhost/ownUploadServer/
		Cookie: JSESSIONID=F0EE9F4C17CB90FCADB60AC34B6AB871; CNZZDATA1000112112=1371504373-1430749960-%7C1430817053; 	</span>
<span style="font-size:14px;">	<span style="white-space: pre;">	</span>Hm_lvt_b24307b87f33ce3e55789d58670dbbd5=1430809410; Hm_lvt_21a80e96f6b0bb699ad5f04db22194a4=1430809411; bdshare_firstime=1431935932462
		Connection: keep-alive</span>
通过观察得知,请求头信息比较重要的是:
<span><span style="font-size:14px;">	</span></span><span style="font-size:14px;">POST /ownUploadServer/doupload.action HTTP/1.1 ,它包括了请求的方式,访问的资源地址,协议的版本。</span>
<span style="font-size:14px;"></span><pre name="code" class="html"><span style="font-size:14px;"><span style="white-space:pre">	</span>Host: localhost ip信息</span>


<span style="font-size:14px;"></span><pre name="code" class="html"><span style="font-size:14px;"><span style="white-space:pre">	</span>Connection: keep-alive 保持连接</span>
<span style="font-size:14px;">
</span>
传过去的参数:
-----------------------------28332323972849 
Content-Disposition: form-data; name="picdesc" 
12 
-----------------------------28332323972849 
Content-Disposition: form-data; name="size" 
23 
-----------------------------28332323972849 
Content-Disposition: form-data; name="ptype" 人文 
-----------------------------28332323972849 
Content-Disposition: form-data; name="pic1"; filename="2.png" 
Content-Type: image/png

xxxx

-----------------------------28332323972849-- 

这里要注意的是协议的拼接非常的严格,一个地方错都会导致程序的崩溃的。

服务器端使用tomcat,客户端是addroid平台,下面实现数据存储:

客户端代码:上传的bean类

public class UploadFile implements Serializable{
	private static final long serialVersionUID = 3445579255260832749L;
	/**
	 *文件的内容
	 */
	private byte[] data;
	/**
	 * 可以通过这个流读数据
	 */
	private InputStream inStream;
	private File file;
	/**
	 * 文件名
	 */
	private String filename;
	/**
	 * 文件类型
	 */
	private String contentType="application/octet-stream";
	private String parameterName;
	
	public UploadFile(byte[] data, String filename, String contentType,
			String parameterName) {
		super();
		this.data = data;
		this.filename = filename;
		this.contentType = contentType;
		this.parameterName = parameterName;
	}

	public UploadFile(File file, String filename, String contentType,
			String parameterName) {
		super();
		this.file = file;
		this.filename = filename;
		this.contentType = contentType;
		this.parameterName = parameterName;
		try {
			this.inStream=new FileInputStream(this.file);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	public byte[] getData() {
		return data;
	}

	public void setData(byte[] data) {
		this.data = data;
	}

	public InputStream getInStream() {
		return inStream;
	}

	public void setInStream(InputStream inStream) {
		this.inStream = inStream;
	}

	public File getFile() {
		return file;
	}

	public void setFile(File file) {
		this.file = file;
	}

	public String getFilename() {
		return filename;
	}

	public void setFilename(String filename) {
		this.filename = filename;
	}

	public String getContentType() {
		return contentType;
	}

	public void setContentType(String contentType) {
		this.contentType = contentType;
	}

	public String getParameterName() {
		return parameterName;
	}

	public void setParameterName(String parameterName) {
		this.parameterName = parameterName;
	}

}
上传帮助类:

package com.yc.utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Map;
import com.yc.bean.UploadFile;;

public class WebUtil {
	/**
	 * 文件上传
	 * @param address
	 * @param params
	 * @param uploadFiles
	 * @throws IOException 
	 * @throws UnknownHostException 
	 */
	public String postFileToServer(String address,Map<String, String> params,List<UploadFile> uploadFiles) throws UnknownHostException, IOException{
		final String BOUNDARY="---------------------------1123240313494";
		final String SEPARATOR="--"+BOUNDARY;
		final String BREAKLINE="\r\n";
		final String ENDLINE=BREAKLINE+SEPARATOR+"--";
		
		long totalLength=0;
		long fileTotalLength=0;
		//计算uploadFiles部分的总长度
		if(uploadFiles!=null&&uploadFiles.size()>0){
			for(UploadFile uf:uploadFiles){
				StringBuffer sb=new StringBuffer();
				sb.append(SEPARATOR);
				sb.append(BREAKLINE);
				sb.append("Content-Disposition: form-data; name=\""+uf.getParameterName()+"\"; filename=\""+ uf.getFilename()+"\"");
				sb.append(BREAKLINE);
				sb.append("Content-Type: "+uf.getContentType());
				sb.append(BREAKLINE).append(BREAKLINE);
				//因为图片数据的后面也要加入一个\r\n
				sb.append(BREAKLINE);
				fileTotalLength+=sb.toString().getBytes().length;
				
				//计算这个uf的真实长度
				if(uf.getInStream()==null){
					fileTotalLength+=uf.getData().length;
				}else{
					fileTotalLength+=uf.getFile().length();
				}
			}
		}
		//计算文本参数部分的总长度
		StringBuffer textEntity=new StringBuffer();
		if(params!=null&¶ms.size()>0){
			for(Map.Entry<String, String> entry:params.entrySet()){
				textEntity.append(SEPARATOR);
				textEntity.append(BREAKLINE);
				textEntity.append("Content-Disposition: form-data; name=\""+entry.getKey()+"\"");
				textEntity.append(BREAKLINE);
				textEntity.append(BREAKLINE);
				textEntity.append(entry.getValue());
				textEntity.append(BREAKLINE);
			}
		}
		
		//总长度
		totalLength=fileTotalLength+textEntity.toString().getBytes().length+ENDLINE.getBytes().length;
		
		//访问网络,发送协议
		URL url=new URL(address);
		//取出端口
		int port=url.getPort()==-1?80:url.getPort();
		//创建socket,以socket套接字访问服务器
		Socket s=new Socket(InetAddress.getByName(url.getHost()),port);
		//取出输入流
		OutputStream oos=s.getOutputStream();
		
		//拼接请求头
		String requestCommand="POST "+url.getPath()+" HTTP/1.1"+BREAKLINE;
		oos.write(requestCommand.getBytes());
		String hostword="Host: "+url.getHost()+BREAKLINE;
		oos.write(hostword.getBytes());
		String connectionword="Connection: keep-alive"+BREAKLINE;
		oos.write(connectionword.getBytes());
		String contenttypeword="Content-Type: multipart/form-data; boundary="+BOUNDARY+BREAKLINE;
		oos.write(contenttypeword.getBytes());
		String contentlength="Content-Length: "+totalLength+BREAKLINE;
		oos.write(contentlength.getBytes());
		//请求头与请求实体间的空行
		oos.write(BREAKLINE.getBytes());
		
		//发出文本实体
		oos.write(textEntity.toString().getBytes());
		
		//发出文件
		//计算出uploadFiles部分的总长度
		if(uploadFiles!=null&&uploadFiles.size()>0){
			for(UploadFile uf:uploadFiles){
				StringBuffer sb=new StringBuffer();
				sb.append(SEPARATOR);
				sb.append(BREAKLINE);
				sb.append("Content-Disposition: form-data; name=\""+uf.getParameterName()+"\"; filename=\""+ uf.getFilename()+"\"");
				sb.append(BREAKLINE);
				sb.append("Content-Type: "+uf.getContentType());
				sb.append(BREAKLINE).append(BREAKLINE);

				//以上是这个文件的文本信息部分
				oos.write(sb.toString().getBytes());
				
				if(uf.getInStream()!=null){
					//以流的形式先读,再用oos写
					byte[] buffer=new byte[1024];
					int length=-1;
					while((length=uf.getInStream().read(buffer,0,buffer.length))!=-1){
						oos.write(buffer,0,length);
					}
				}else{
					oos.write(uf.getData(),0,uf.getData().length);
				}
				oos.write(BREAKLINE.getBytes());
				oos.flush();
			}
		}
		//还有一个结束行
		oos.write(ENDLINE.getBytes());
		oos.flush();
		
		//接收服务器的回应
		InputStream iis=s.getInputStream();
		String result=new String();
		int len=-1;
		byte[] b=new byte[1024];
		while((len=iis.read(b,0,b.length))!=-1){
			result+=new String(b,0,len);
		}
		oos.close();
		iis.close();
		s.close();
		
		return result;
	}
}

然后在主界面调用的如下:这个要注意的是android在高版本的时候在上传文件到网络的时候,必须要开启新的线程而不能再主线程中操作。

我用的是handler类通过消息机制操作线程,也是可以通过AsyncTask操作。

线程代码如下:

btn4.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				new Thread(new Runnable() {
					@Override
					public void run() {
						Map<String , String>params=new HashMap<String, String>();
						Person p =(Person)FilesUtils.getObjectFromFile("xiaofeng", MainActivity2.this);
						params.put("name", p.getName());
						params.put("age", p.getAge()+"");
						params.put("sex", p.getSex());
						List<UploadFile>uploadFiles=new ArrayList<UploadFile>();
						File headFile=new File(p.getHeadpic());
						String filename=headFile.getName();
						uploadFiles.add(new UploadFile(headFile, filename, "image/jpeg", "headpic"));

						WebUtil wu=new WebUtil();
						try {
							String responseprotocol=wu.postFileToServer("http://211.69.255.66/ownUploadServer/doupload.action", params, uploadFiles);
							Message m=new Message();
							m.what=1;
							m.obj=responseprotocol;
							handler.sendMessage(m);
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}).start();
Hannler的实例如下:

private Handler handler=new Handler(){
		public void handleMessage(android.os.Message msg) {
			switch(msg.what){
			case 1:
				String response=(String) msg.obj;
				if(response.indexOf("200")>0){
					Toast.makeText(MainActivity2.this, "上传云端成功", 3000).show();
				}
			}
		}
	};
值得一提的是:android在发送数据到服务器的时候,一定不能写localhost,因为localhost已经被android模拟器占用了,只能用ip地址,而且如果是真机测试的话,还要保证手机的网段和电脑的网段一致,并且关闭防火墙。才能测试成功。。


通过学习android的网络存储,对协议有更深的了解了,加油






Android 数据存储五种方式使用与总结

部分内容来源于官方文档翻译, 对SharedPreferences; 文件存储(内部存储读写,保存编译文件,保存内存缓存文件,外部存储读写); SQLite使用; ContentProvider使用;...
  • Amazing7
  • Amazing7
  • 2016年05月18日 16:06
  • 30157

Android数据存储网络存储数据

Android提供了通过网络来实现数据的存储和获取的方法。  我们可以调用WebService返回的数据或是解析HTTP协议实现网络数据交互。  具体需要熟悉java.net.*,Android....
  • liranke
  • liranke
  • 2012年06月17日 11:59
  • 10282

Android存储五大方式

Android存储五大方式: 1 使用SharedPreferences存储数据  2 文件存储数据  3 SQLite数据库存储数据  4 使用ContentProvider...
  • qq_33094497
  • qq_33094497
  • 2016年08月29日 11:03
  • 1147

Android数据存储五种方式总结

本文介绍Android平台进行数据存储的五大方式,分别如下:        1 使用SharedPreferences存储数据     2 文件存储数据           3 ...
  • xjbclz
  • xjbclz
  • 2016年11月05日 16:51
  • 688

android的五种存储方式SharedPreferences、文件存储、SQLite数据库、ContentProvider、网络存储

第一种: 使用SharedPreferences存储数据     适用范围:保存少量的数据,且这些数据的格式非常简单:字符串型、基本类型的值。比如应用程序的各种配置信息(如是否打开音效、是否使用震动...
  • meijuanyou
  • meijuanyou
  • 2016年03月22日 19:15
  • 1838

android存储之网络存储和数据库存储

昨天说老师说了android的网络存储,对协议有了一个更深的理解。 数据上传到网络,尽管 b/s 和c/s的架构不一样,但是它们还是能上传数据到网络,因为都遵循协议的规范,c/s存储数据到网络,思想...
  • Watering_sea
  • Watering_sea
  • 2015年07月09日 10:37
  • 815

文件和数据库存储数据的速度比较

While writing Inklog, I’ve been debating with myself regarding my use of the filesystem as a datasto...
  • guofeng13
  • guofeng13
  • 2007年04月24日 09:33
  • 1805

数据库关系式存储和分布式存储区别

数据库关系式存储和分布式存储区别:应用目标不同、 实现方式不同、各结点的地位不同。 (1) 应用目标不同。并行数据库系统的目标是充分发挥并行计算机的优势,利用系统中的各个处理机结点并行完成数...
  • baidu_17201253
  • baidu_17201253
  • 2016年07月25日 16:30
  • 1323

Android中的5种数据存储方式

数据存储在开发中是使用最频繁的,在这里主要介绍Android平台中实现数据存储的5种方式,分别是: 1 使用SharedPreferences存储数据 2 文件存储数据 3 SQLite数据库存...
  • Sindyue
  • Sindyue
  • 2016年04月04日 17:12
  • 1467

Android几种数据存储方式的应用场景

作为一个完整的应用程序,数据存储操作是必不可少的。因此,Android系统一共提供了四种数据存储方式。分别是:SharePreference、SQLite、 Content Provider、File...
  • goodlixueyong
  • goodlixueyong
  • 2015年07月24日 15:03
  • 9083
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:android存储之网络存储和数据库存储
举报原因:
原因补充:

(最多只允许输入30个字)