Android基础学习__第2天__数据的存储与访问
2013-10-21 13:25
549 查看
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; }
相关文章推荐
- android启动速度优化
- Android JNI ,将java 实例与c实例绑定
- 浅析Android中Intent以及Intent Filter的运用
- Android主题切换
- Android同步类:Mutex和Condition
- android activity横竖屏切换,Activity重新创建问题解决!
- android activity横竖屏切换,Activity重新创建问题解决!
- android:ScrollView嵌套ListView的问题
- NOTE:Android Styles and Themes的一些需要注意的小细节
- Android 在一个程序中启动另一个程序和启动另一个程序的服务
- android 中Dialog的一些用法
- Android 隐藏程序的图标
- Android代码片段收集
- Android数据库安全解决方案,使用SQLCipher
- Android数据库安全解决方案,使用SQLCipher
- android soundrecorder之四 dapm介绍
- 近百个Android优秀开源项目,覆盖Android开发的每个领域
- Android之ProgressBar、SeekBar、RatingBar
- android usb与自定义HID设备通讯
- Android之高仿手机QQ聊天