Android基础学习__第2天__数据的存储与访问


1.文件存储

    保存文件到手机内存

    Context接口:字面意思上下文,提供了关于应用环境全局信息的接口。它是一个抽象类,它的执行被Android系统所提供。它允许获取以应用为特征的资源和类型。同时启动应用级的操作,如启动Activity,broadcasting和接收intents。

    context.getFileDir():帮助我们返回一个目录(data/data/包名/files/)

    context.getCacheDir():帮助我们返回一个目录(data/data/包名/cache/)

    Android文件操作模式:

Context.MODE_PRIVATE = 0:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中。可以使用Context.MODE_APPEND。
Context.MODE_APPEND = 32768:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。
Context.MODE_WORLD_READABLE = 1和Context.MODE_WORLD_WRITEABLE = 2用来控制其他应用是否有权限读写该文件。
Context.MODE_WORLD_READABLE:表示当前文件可以被其他应用读取;
Context.MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。

//如果希望文件被其他应用读和写,可以传入: 
openFileOutput("itcast.txt", Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE);
    Android有一套自己的安全模型,当应用程序(.apk)在安装时系统就会分配给他一个userid,当该应用要去访问其他资源比如文件的时候,就需要userid匹配。默认情况下,任何应用创建的文件,sharedpreferences,数据库都应该是私有的(位于/data/data/<package name>/files),其他程序无法访问。除非在创建时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE ,只有这样其他程序才能正确访问。
保存文件:
public static boolean saveUserInfo(Context context, String username,String password){
	try {
		//得到一个目录 /data/data/当前应用程序包名/files/

		//第一种方法:
		//File file = new File(context.getFileDir(),"info.dat");
		//FileOutputStream fos = new FileOutputStream(file);
		
		//第二种方法:调用context下的operFileOutput(String 文件名,访问权限)
		FileOutputStream fos = context.openFileOutput("info.dat", Context.MODE_PRIVATE);

		fos.write((username+"##"+password).getBytes());
		fos.close();
		return true;
	} catch (Exception e) {
		e.printStackTrace();
		return false;
	}
}
读取文件:
public static Map<String,String> readUserInfo(Context context){
	try {
		File file = new File(context.getFileDir(),"info.dat");
		FileInputStream fis = new FileInputStream(file);
		//FileInputStream fis = context.openFileInput("info.dat");
		BufferedReader br = new BufferedReader(new InputStreamReader(fis));
		String line = br.readLine();
		String username = line.split("##")[0];
		String password = line.split("##")[1];
		Map<String, String> map = new HashMap<String, String>();
		map.put("username", username);
		map.put("password", password);
		return map;
	} catch (Exception e) {
		e.printStackTrace();
		return null;
	}		
}

    保存文件到SD卡

    与保存到手机内存不一样的是,保存文件到SD卡需要相关权限:

    写:<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
    读:<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> (Android4.0出现,4.0之前可以不用请求这个权限而对文件进行读取)

    将相关权限代码添加至AndroidManifest.xml文件中

    查看SD卡状态方法:Environment.getExternalStorageState(),返回的是描述SD卡状态的字符串

    Environment.MEDIA_MOUNTED:可读可写

相关代码:
public static boolean saveUserInfo(Context context,String username,String password){
	try{
		//判断SD卡状态
		if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){
			//Environment.getExternalStorageDirectory()得到SD卡路径
			File file = new File(Environment.getExternalStorageDirectory(),"/info.dat");
			FileOutputStream fos = new FileOutputStream(file);
			// zhangsan##123
			fos.write((username+"##"+password).getBytes());
			fos.close();
			return true;
		}else{
			Toast.makeText(context,"sd卡不可用,请检查sd卡状态",0).show();
		}
		
	} catch (Exception e) {
		e.printStackTrace();
		return false;
	}
}
获取内存大小:
package com.itheima.calcsize;

import java.io.File;

import android.os.Bundle;
import android.os.Environment;
import android.os.StatFs;
import android.app.Activity;
import android.text.format.Formatter;
import android.view.Menu;
import android.widget.TextView;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		TextView tv_info = (TextView) findViewById(R.id.tv_info);
		tv_info.setText("sd卡可用:"+getAvailSDSize()+"\n"+"内存可用:"+getAvailROMSize());
	}

	/**
	 * 获取sd卡的可用空间
	 * @return
	 */
	private String getAvailSDSize() {
		//得到SD卡路径
		File path = Environment.getExternalStorageDirectory();
		//获取路径所指向的文件系统状态
		StatFs stat = new StatFs(path.getPath());
		//得到每一块的大小
		long blockSize = stat.getBlockSize();
		//得到可用有多少块
		long availableBlocks = stat.getAvailableBlocks();

		//得到总共多少块
		//long totalBolcks = stat.getBlocksCount();

		//计算出可用内存大小,单位byte
		long availablesize = blockSize * availableBlocks; // byte
		//将数据格式化并返回
		return Formatter.formatFileSize(this, totalsize);
	}
	/**
	 * 获取手机内部存储rom的可用空间
	 * @return
	 */
	private String getAvailROMSize() {
		//得到手机内存路径
		File path = Environment.getDataDirectory();
		//获取路径所指向的文件系统状态
		StatFs stat = new StatFs(path.getPath());
		//得到每一块的大小
		long blockSize = stat.getBlockSize();
		//得到可用有多少块
		long availableBlocks = stat.getAvailableBlocks();

		//得到总共多少块
		//long totalBolcks = stat.getBlocksCount();

		//计算出可用内存大小,单位byte
		long totalsize = blockSize * availableBlocks; // byte
		//将数据格式化并返回
		return Formatter.formatFileSize(this, totalsize);
	}
}

2.SharedPreferences

    SharedPreferences是一种轻型的数据存储方式,它的本质是基于XML文件存储key-value键值对数据,通常用来存储一些简单的配置信息。其存储位置在/data/data/<包名>/shared_prefs目录下。SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过Editor对象实现。实现SharedPreferences存储的步骤如下:
    1.根据Context获取SharedPreferences对象
    2.利用edit()方法获取Editor对象。
    3.通过Editor对象存储key-value键值对数据。
    4.通过commit()方法提交数据。

保存文件:

public static void saveUserInfo(Context context,String username,String password){
	SharedPreferences sp = context.getSharedPreferences("config",Context.MODE_PRIVATE);

	//得到编辑器
	Editor editor = sp.edit();
	//添加信息
	editor.putString("username",username);
	editor.putString("password",password);
	//提交保存数据
	editor.commit();
}
    调用以上方法后,会在/data/data/(包名)/shared_prefs目录下生成了一个config.xml文件,一个应用可以创建多个这样的xml文件,保存文件格式如下:
  <?xml version="1.0" encoding="utf-8" standalone="yes" ?> 
- <map>
  <string name="password">123</string> 
  <string name="username">wangwu</string> 
  </map>
读取文件:
SharedPreferences sp = context.getSharedPreferences("config",Context.MODE_PRIVATE);
//第二个参数为缺省值
String username = sp.getString("username","");
String password = sp.getString("password","");
    SharedPreferences有其自身缺陷,比如其只能存储boolean,int,float,long和String五种简单的数据类型,并且不能像SQLite进行条件查询。

3.XML文件序列化

    通过备份短信演示XML文件序列化的各种方法。将短信的各种信息备份至XML文件中,格式如下图:


手动将短信数据写入xml文件的方法

public void click(View view){
	StringBuilder sb = new StringBuilder();
	sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
	sb.append("<smss>");
	for(SmsInfo info : smsInfos){
		sb.append("<sms>");
		
		sb.append("<body>");
		sb.append(info.getBody());
		sb.append("</body>");
			
		sb.append("<address>");
		sb.append(info.getAddress());
		sb.append("</address>");
			
		sb.append("<date>");
		sb.append(info.getDate());
		sb.append("</date>");
			
		sb.append("</sms>");
	}
	sb.append("</smss>");
		
	try {
		File file = new File(Environment.getExternalStorageDirectory(),"backup.xml");
		FileOutputStream fos = new FileOutputStream(file);
		fos.write(sb.toString().getBytes());
		fos.close();
		Toast.makeText(this, "备份短信成功", 0).show();
	} catch (Exception e) {
		e.printStackTrace();
		Toast.makeText(this, "备份短信失败", 0).show();
	}
}
    以上方法是使用StringBuilder进行字符串添加,然后写入文件,这种方式的缺点就是在对xml进行属性设置的时候非常麻烦,下面使用xml文件的序列化器进行xml文件的创建。

public void click(View view){
	try {
		//1,初始化一个xml文件的序列化器
		XmlSerializer serializer = Xml.newSerializer();
		//2.初始化序列器参数,并且指定文件的编码方式
		File file = new File(Environment.getExternalStorageDirectory(),"backup.xml");
		FileOutputStream fos = new FileOutputStream(file);
		serializer.setOutput(fos, "UTF-8");
		//3.开始写xml文件.
		serializer.startDocument("UTF-8", true);//文件头,true代表是否独立
		//开始节点
		serializer.startTag(null, "smss");
		for(SmsInfo info : smsInfos){
			serializer.startTag(null, "sms");
			//添加属性
			serializer.attribute(null,"id",info.getId()+"");
				
			serializer.startTag(null, "body");
			serializer.text(info.getBody());
			serializer.endTag(null, "body");
				
				
			serializer.startTag(null, "address");
			serializer.text(info.getAddress());
			serializer.endTag(null, "address");
				
			serializer.startTag(null, "date");
			serializer.text(info.getDate()+"");
			serializer.endTag(null, "date");
				
			serializer.endTag(null, "sms");
		}
		//结束节点
		serializer.endTag(null, "smss");
		//xml文件结尾
		serializer.endDocument();
		fos.close();
			
		Toast.makeText(this, "备份成功", 0).show();
	} catch (Exception e) {
		e.printStackTrace();
		Toast.makeText(this, "备份失败", 0).show();
	}
			
}
    使用xml的序列化器XmlSerializer还有一个好处就是在序列化诸如“<”这样的字符的时候会自动替换成相应可以被xml解析的字符.

    使用pull解析器解析xml文件

    Pull解析器是一个开源的java项目,既可以用于android,也可以用于JavaEE。如果用在javaEE需要把其jar文件放入类路径中,因为Android已经集成进了Pull解析器,所以无需添加任何jar文件。android系统本身使用到的各种xml文件,其内部也是采用Pull解析器进行解析的。 Pull解析器的运行方式与 SAX 解析器相似。它提供了类似的事件,如:开始元素和结束元素事件,使用parser.next()可以进入下一个元素并触发相应事件。跟SAX不同的是, Pull解析器产生的事件是一个数字,而非方法,因此可以使用一个switch对感兴趣的事件进行处理。当元素开始解析时,调用parser.nextText()方法可以获取下一个Text类型节点的值。

解析短信Xml文件:

public static List<SmsInfo> getSmsInfos(InputStream is) throws Exception{
	XmlPullParser parser = Xml.newPullParser();
	//初始化解析器
	parser = setInput(is,"utf-8"); 
	List<SmsInfo> smsInfos = null;
	SmsInfo smsInfo = null
	//得到当前事件类型:0代表文档开头,1代表文档结尾
	int type = parser.getEventType();
	while(type!=XmlPullParser.END_DOCUMENT)
	{
		switch(type){
			case XmlPullParser.START_TAG:
				if("smss".equalse(parser.name())){
					smsInfos = new ArrayList<SmsInfo>();
				}else if("sms".equalse(parser.getName())){
					smsInfo = new SmsInfo();
				}else if("body".equalse(parser.getName())){
					String body = parser.nextText();
					smsInfo.setBody(body);
				}else if("date".equalse(parser.getName())){
					String date = parser.nextText();
					smsInfo.setDate(date);
				}else if("type".equalse(parser.getName())){
					String type = parser.nextText();
					smsInfo.setType(type);
				}else if("address".equalse(parser.getName())){
					String address = parser.nextText();
					smsInfo.setAddress(address);
				}
			case XmlPullParser.END_TAG:
				if("sms".equals(parser.name())){
					smsInfos.add(smsInfo);
					snsInfo = null;
				}
		}
		
		type = parser.next();	

	}
	return smsInfos;

}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值