前言

  之前一直在讲AndroidUI的内容,但是还没有完结,之后会慢慢补充。今天讲讲其他的,关于数据持久化的内容。对于一个应用程序而言,不可避免的要能够对数据进行存储,Android程序也不例外。而在Android中,提供了几种实现数据持久化的方法。后面会分别介绍。

  在Android中,可以使用几种方式实现数据持久化:

  • Shared Preferences:共享参数形式,一种以Key-Value的键值对形式保存数据的方式,Android内置的,一般应用的配置信息,推荐使用此种方式保存。
  • Internal Storage:使用Android设备自带的内存存储数据。
  • External Storage:使用外部存储设备存储数据,一般是指Sdcard。
  • SQLite Databases:以SQLite数据库存储结构化的数据。
  • Network Connection:使用基于网络的服务获取数据,可以参见另外一篇博客:Android--Apache HttpClient。

  后面几天会分别介绍以上几种方式实现的数据持久化,对于SharedPreferences而言,之前写过一篇博客,但是自己不是很满意,之后有时间会再重新写一份关于SharedPreferences的博客,有兴趣的朋友可以先去看看,Android--使用SharedPreferences。今天先介绍Internal Storage以及External Storage。

Internal Storage

  内部存储,在Android中,开发者可以直接使用设备的内部存储器中保存文件,默认情况下,以这种方式保存的和数据是只能被当前程序访问,在其他程序中是无法访问到的,而当用户卸载该程序的时候,这些文件也会随之被删除。

  使用内部存储保存数据的方式,基本上也是先获得一个文件的输出流,然后以write()的方式把待写入的信息写入到这个输出流中,最后关闭流即可,这些都是Java中IO流的操作。具体步骤如下:

  • 使用Context.openFileOutput()方法获取到一个FileOutputStream对象。
  • 把待写入的内容通过write()方法写入到FileOutputStream对象中。
  • 最后使用close()关闭流。

  上面介绍的Context.openFileOutput()方法有两个重载函数,它们的签名分别是:

  • FileOutputStream openFileOutput(String name):以MODE_PRIVATE的模式打开name文件。
  • FileOutputStream openFileOutput(String name,int mode):以mode的模式打开name文件。

  上面第二个重载函数中,mode为一个int类型的数据,这个一般使用Context对象中设置好的常量参数,有如下几个:

  • MODE_APPEND:以追加的方式打开一个文件,使用此模式写入的内容均追加在原本内容的后面。
  • MODE_PRIVATE:私有模式(默认),如果文件已经存在会重新创建并替换原文件,如果不存在直接创建。
  • MODE_WORLD_READABLE:以只读的方式打开文件。
  • MODE_WORLD_WRITEABLE:以只写的方式打开文件。

  还有几个方法需要特别注意一下,这几个方法对于文件关系提供了更好的支持,配合上面介绍的方式,就可以对文件的数据进行常规的CRUD操作(增删改查),方法如下:

  • File getFIlesDir():获取文件系统的绝对路径。
  • boolean deleteFile(String name):删除一个指定文件名为name的文件。
  • String[] fileList():当前应用内部存储路径下的所有文件名。

  讲了这么多,下面通过一个简单的Demo来演示一下上面提到的内容。在这个Demo中,指定文件名和内容,既可创建文件,并且可以对其内容进行追加、修改、删除、查询等操作。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content" android:text="file name:" /> <EditText android:id="@+id/etInternalFilename" android:layout_width="match_parent" android:layout_height="wrap_content" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Content:" /> <EditText android:id="@+id/etInternalContent" android:layout_width="match_parent" android:layout_height="wrap_content" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <Button android:id="@+id/btnInternalSave" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="save" /> <Button android:id="@+id/btnInternalDelete" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="delete" /> <Button android:id="@+id/btnInternalAppend" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="append" /> <Button android:id="@+id/btnInternalQuery" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="query" /> </LinearLayout> <!-- 以一个ListView的形式展示当前程序内部存储路径下的所有文件 --> <ListView android:id="@+id/lvInternalData" android:layout_width="match_parent" android:layout_height="fill_parent" > </ListView> </LinearLayout>

View Code

内部存储的操作类,对其实现CRUD操作:

package com.example.internal;import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import android.content.Context; import android.os.Environment; import android.util.Log; public class MyInternalStorage { //需要保存当前调用对象的Context private Context context; public MyInternalStorage(Context context) { this.context = context; } /** * 保存内容到内部存储器中 * @param filename 文件名 * @param content 内容 */ public void save(String filename, String content) throws IOException { // FileOutputStream fos=context.openFileOutput(filename, // Context.MODE_PRIVATE); File file = new File(context.getFilesDir(), filename); FileOutputStream fos = new FileOutputStream(file); fos.write(content.getBytes()); fos.close(); } /** * 通过文件名获取内容 * @param filename 文件名 * @return 文件内容 */ public String get(String filename) throws IOException { FileInputStream fis = context.openFileInput(filename); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] data = new byte[1024]; int len = -1; while ((len = fis.read(data)) != -1) { baos.write(data, 0, len); } return new String(baos.toByteArray()); } /** * 以追加的方式在文件的末尾添加内容 * @param filename 文件名 * @param content 追加的内容 */ public void append(String filename, String content) throws IOException { FileOutputStream fos = context.openFileOutput(filename, Context.MODE_APPEND); fos.write(content.getBytes()); fos.close(); } /** * 删除文件 * @param filename 文件名 * @return 是否成功 */ public boolean delete(String filename) { return context.deleteFile(filename); } /** * 获取内部存储路径下的所有文件名 * @return 文件名数组 */ public String[] queryAllFile() { return context.fileList(); } }

View Code

Activity代码:

package com.internalstorageactivity;import java.io.IOException;import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.Toast; public class InternalStorageActivity extends Activity { private EditText etFilename, etContent; private Button btnSave, btnQuery, btnDelete, btnAppend; private ListView lvData; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); lvData = (ListView) findViewById(R.id.lvInternalData); lvData.setOnItemClickListener(new OnItemClickListener(){ @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { System.out.println("1"); ListView lv = (ListView) parent; ArrayAdapter<String> adapter = (ArrayAdapter<String>) lv .getAdapter(); String filename = adapter.getItem(position); etFilename.setText(filename); MyInternalStorage myInternal = new MyInternalStorage( InternalStorageActivity.this); try { String content = myInternal.get(filename); etContent.setText(content); } catch (IOException e) { // TODO Auto-generated catch block  e.printStackTrace(); } } }); etFilename = (EditText) findViewById(R.id.etInternalFilename); etContent = (EditText) findViewById(R.id.etInternalContent); btnSave = (Button) findViewById(R.id.btnInternalSave); btnSave.setOnClickListener(new OnClickListener() { String filename = null; String content = null; public void onClick(View v) { filename = etFilename.getText().toString(); content = etContent.getText().toString(); MyInternalStorage myInternal = new MyInternalStorage( InternalStorageActivity.this); try { myInternal.save(filename, content); Toast.makeText(InternalStorageActivity.this, "保存文件成功", Toast.LENGTH_SHORT).show(); } catch (IOException e) { // TODO Auto-generated catch block  e.printStackTrace(); Toast.makeText(InternalStorageActivity.this, "保存文件失败", Toast.LENGTH_SHORT).show(); } } }); btnAppend = (Button) findViewById(R.id.btnInternalAppend); btnAppend.setOnClickListener(new OnClickListener() { String filename = null; String content = null; public void onClick(View v) { filename = etFilename.getText().toString(); content = etContent.getText().toString(); MyInternalStorage myInternal = new MyInternalStorage( InternalStorageActivity.this); try { myInternal.append(filename, content); Toast.makeText(InternalStorageActivity.this, "保存内容追加成功", Toast.LENGTH_SHORT).show(); } catch (IOException e) { // TODO Auto-generated catch block  e.printStackTrace(); Toast.makeText(InternalStorageActivity.this, "文件内容追加失败", Toast.LENGTH_SHORT).show(); } } }); btnQuery = (Button) findViewById(R.id.btnInternalQuery); btnQuery.setOnClickListener(new OnClickListener() { public void onClick(View v) { MyInternalStorage myInternal = new MyInternalStorage( InternalStorageActivity.this); String[] files = myInternal.queryAllFile(); ArrayAdapter<String> fileArray = new ArrayAdapter<String>( InternalStorageActivity.this, android.R.layout.simple_list_item_1, files); lvData.setAdapter(fileArray); Toast.makeText(InternalStorageActivity.this, "查询文件列表", Toast.LENGTH_SHORT).show(); } }); btnDelete = (Button) findViewById(R.id.btnInternalDelete); btnDelete.setOnClickListener(new OnClickListener() { public void onClick(View v) { String filename = etFilename.getText().toString(); ; MyInternalStorage myInternal = new MyInternalStorage( InternalStorageActivity.this); myInternal.delete(filename); Toast.makeText(InternalStorageActivity.this, "删除文件成功", Toast.LENGTH_SHORT).show(); } }); } }

View Code

使用内部存储的方式进行数据持久化,文件的地址将保存在/data/data/<package_name>/files/路径下,上面创建了三个文件,最后删掉了一个,如果是使用的模拟器,可以直接在File Explorer中查看:

缓存(cache)

  既然提到了内部存储,这里再简单的说说关于缓存文件(cache files)。cache files的操作与操作内部存储中的文件方式基本一致,只是获取文件的路径有说不同。如果需要使用缓存的方式进行数据持久话,那么需要使用Context.getCacheDir()方法获取文件保存的路径。

  对于缓存文件而言,当设备内部内存存储空间不足的时候,Android会有自动删除的机制删除这些缓存文件,用来恢复可用空间,所以对于缓存文件而言,内容一般最好控制在1MB之下,并且也不要存放重要的数据,因为很可能下次去取数据的时候,已经被Android系统自动清理了。

External Storage

  使用外部存储实现数据持久化,这里的外部存储一般就是指的是sdcard。使用sdcard存储的数据,不限制只有本应用访问,任何可以有访问Sdcard权限的应用均可以访问,而Sdcard相对于设备的内部存储空间而言,会大很多,所以一般比较大的数据,均会存放在外部存储中。

  使用SdCard存储数据的方式与内部存储的方式基本一致,但是有三点需要注意的:

  • 第一点,需要首先判断是否存在可用的Sdcard,这个可以使用一个访问设备环境变量的类Environment进行判断,这个类提供了一系列的静态方法,用于获取当前设备的状态,在这里获取是否存在有效的Sdcard,使用的是Environment.getExternalStorageState()方法,返回的是一个字符串数据,Environment封装好了一些final对象进行匹配,除了Environment.MEDIA_MOUNTED外,其他均为有问题,所以只需要判断是否是Environment.MEDIA_MOUNTED状态即可。
  • 第二点,既然转向了Sdcard,那么存储的文件路径就需要相对变更,这里可以使用Envir.getExternalStorageDirectory()方法获取当Sdcard的根目录,可以通过它访问到相应的文件。
  • 第三点,需要赋予应用程序访问Sdcard的权限,Android的权限控制尤为重点,在Android程序中,如果需要做一些越界的操作,均需要对其进行授权才可以访问。在AndroidManifest.xml中添加代码:<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>  

  因为访问Sdcard的方式和访问内部存储的方式差不多,这里就展示一个Save的方法,用于保存文件,其他CRUD操作,这里就不再一一给出了。

  

public void saveToSdcard(String filename, String content) throws IOException {if (Environment.MEDIA_MOUNTED.equals(Environment .getExternalStorageState())) { Log.i("main", "本设备有存储卡!"); File file = new File(Environment.getExternalStorageDirectory(), filename); FileOutputStream fos = null; fos = new FileOutputStream(file); fos.write(content.getBytes()); fos.close(); } }

View Code

而如果使用SdCard存储文件的话,存放的路径在Sdcard的根目录下,如果使用模拟器运行程序的话,创建的文件在/mnt/sdcard/目录下:

  补充:对于现在市面上很多Android设备,自带了一个大的存储空间,一般是8GB或16GB,并且又支持了Sdcard扩展,对于这样的设备,使用Enviroment.getExternalStorageDirectory()方法只能获取到设备自带的存储空间,对于另外扩展的Sdcard而言,需要修改路径。

转自:http://www.cnblogs.com/weixing/p/3243115.html

Android--数据持久化之内部存储、Sdcard存储相关推荐

  1. Android数据持久化存储

    Android数据持久化存储共有四种方式,分别是文件存储.SharedPreferences.Sqlite数据库和ContentProvider.在本篇幅中只介绍前面三种存储方式,因为ContentP ...

  2. Android数据持久化

    Android数据持久化(存储) 1.SharedPreferences SharedPreferences是Android提供的数据持久化的一种手段,适合单进程.小批量的数据存储与访问.Shared ...

  3. Android之获取手机内部及sdcard存储空间

    Android之获取手机内部及sdcard存储空间 文章链接 知识点: 内部存储空间获取总大小和可用大小: sdcard存储空间获取总大小和可用大小: 新名词记录{StatFs:描述文件系统信息的类} ...

  4. Android数据持久化:SharePreference

    SharePreference:作为Android数据持久化的一种,具有一定的便捷性,适合存储一些体积小的数据. 存储数据方式:键值对的方式,类似于Map: 利用SharePreference.Edi ...

  5. Android数据持久化技术

    Android 数据持久化技术 数据持久化 文件存储 将数据存储到文件中 从文件中读取数据 SharedPreferences存储 使用SharedPreferences存储数据 从SharedPre ...

  6. android 清空数组缓存,Android数据持久化之读写SD卡中内容的方法详解

    本文实例讲述了Android数据持久化之读写SD卡中内容的方法.分享给大家供大家参考,具体如下: 前面文章里讲的那三个方法:openFileOutput.openFileInput虽然都能通过流对象O ...

  7. android数据持久化框架,Android:数据持久化、Environment、SharedPreferences、内部存储internalStorage...

    1.数据持久化-SDCard//数据持久化-SDCard findViewById(R.id.button1).setOnClickListener(new OnClickListener() { @ ...

  8. 文件存储管理 android,Android数据持久化之文件存储

    一. 文件存储路径分类 1. 内部存储 内部存储是指在system分区(根目录)下的data/data/package name/下的文件. 这层目录普通用户和程序一般无法直接访问,当前应用的文件也只 ...

  9. Android数据持久化:文件存储

    数据持久化: 数据可分为瞬时数据和关键数据.保存在内存之中的数据是瞬时数据,而对于一些关键性数据,后期需要持续使用的,应当保存在存储设备中: 持久化保存方式: 文件存储.SharePreference ...

  10. Android—数据持久化、SP源码

    3种数据持久化: File:openFileInput(String fileName).openFileOutput(String fileName, int mode) 不对存储的内容进行任何的格 ...

最新文章

  1. mysql binlog 恢复指定表_Mysql用全备恢复指定表mysqlbinlog抽取某个表的信息
  2. java窗体容器坐标_Java的屏幕坐标是以像素为单位的,容器的左下角被确定为坐标的起点。...
  3. 自学Python:截取屏幕画面
  4. linux怎么看java环境变量_linux下配置jdk环境变量以及查看java版本
  5. 计算机应用基础第十一版答案,计算机应用基础 11.doc
  6. git的配置与基本使用
  7. android菜单动画,利用 android studio 制作一个菜单动画
  8. layui让当前页面刷新_layui点击按钮页面会自动刷新的解决方案
  9. HDU 5980 位运算 进制转换函数 DEV C++调试失败的原因
  10. vue模块单独封装html,在vue中怎么定义自定义组件?
  11. dll反编译工具java_JAVA反编译工具的使用
  12. JS addEventListener()方法
  13. Flask 源码解析:session
  14. Android实例-手机安全卫士(四十一)-选择自定义Toast背景
  15. 快讯 | Elon Musk拟跨界做喜剧,号称要建立跨星系传媒帝国Thud!(轰!)
  16. 【附源码】计算机毕业设计SSM社区生鲜电商平台
  17. 数学建模语言AMPL及其应用
  18. Redis分片入门案例
  19. DevStack环境搭建
  20. D2550运行Linux,也发一个128*128的相框lcd4linux的conf

热门文章

  1. 你不知道的接口测试之简单的开始
  2. 一个老测试给想入行测试行业新人的二十条建议
  3. 2021秋季跳槽必备:软件测试面试题(附带答案)备战金九银十!
  4. 健康评测 php,8款超好用的健康APP测评推荐!
  5. Deformable 3D shape registration based on local similarity transforms
  6. GPT2模型训练,50w个多轮中文对话语料
  7. YOLO3 动漫人脸识别
  8. 【免费】某平台3980元大数据课程免费下载,仅此1次
  9. 机器学习常见算法优缺点汇总
  10. python的哲学内容_python 哲学或者说文化