Android学习 —— 数据的存储与访问方式一: 文件存取
笔记摘要:
在Android中主要提供了四种数据存储与访问的方式,文件、SharedPreference(偏好参数保存)、SOLite数据库、内容提供者(Content provider)和网络,
本篇文章先介绍使用文件的方式进行数据的存储和访问,其中重点介绍了它的四种操作模式。
使用文件进行存储
方式一:通过openFileOutput()直接把数据输出到文件中
Activity提供了openFileOutput()方法可以用于把数据输出到文件中,具体的实现过程与在J2SE环境中保存数据到文件中是一样的
public class FileActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { ... FileOutputStream outStream = this.openFileOutput("test.txt", Context.MODE_PRIVATE); outStream.write("这是一个使用文件进行存储的示例".getBytes()); outStream.close(); } }
openFileOutput()方法的第一参数用于指定文件名称,不能包含路径分隔符“/” ,如果文件不存在,Android 会自动创建它。
创建的文件保存在/data/data/<package name>/files目录:openFileOutput()。方法的第二参数用于指定操作模式.
方式二:通过getFilesDir()先获取文件的路径:/data/data/<package name>/files目录
public static boolean saveInfoToFile(Context context){ try { File parentfile = context.getFilesDir();// /data/data/com.itxushuai.login/files File des = new File(parentfile,"info.txt");// /data/data/com.itxushuai.login/files/info.txt FileOutputStream fos = new FileOutputStream(des); fos.write("文件存入".getBytes()); fos.close(); return true ; } catch (Exception e) { e.printStackTrace(); return false; }
文件操作的有四种模式:
Context.MODE_PRIVATE = 0
Context.MODE_APPEND = 32768
Context.MODE_WORLD_READABLE = 1
Context.MODE_WORLD_WRITEABLE = 2
Context.MODE_PRIVATE:
为默认操作模式,由PRIVATE就可知道该文件是私有的,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,
如果想把新写入的内容追加到原文件中。可以使用Context.MODE_APPEND
Context.MODE_APPEND:
模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。
Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE用来控制其他应用是否有权限读写该文件。
MODE_WORLD_READABLE:
表示当前文件可以被其他应用读取。
MODE_WORLD_WRITEABLE:
表示当前文件可以被其他应用写入。
如果希望文件被其他应用读和写,可以将READABLE 与WRITEABLE组合起来使用:
openFileOutput("file.txt",Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE);
Tip
android有一套自己的安全模型,当应用程序(.apk)在安装时系统就会分配给他一个userid,当该应用要去访问其他资源比如文件的时候,就需要userid匹配。默认情况下,任何应用创建的文件,sharedpreferences,数据库都应该是私有的(位于/data/data/<package name>/files),其他程序无法访问。除非在创建时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE ,只有这样其他程序才能正确访问。
示例演示:
说明:
1)模拟用户登陆界面,向文件中写入用户的用户名和密码,并在用户下一次登陆的时候,实现回显功能。
2)向SD卡中写入文件,记得在AndroidMainfest.xml文件中配置读写权限。
3)四种模式文件的写入
配置权限
<!--在manifest节点下添加SD卡写入和读取权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/username"/> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="text" android:id="@+id/username_et" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/password" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textPassword" android:id="@+id/password_et" /> <RadioGroup android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/radioGroup_id" > <RadioButton android:text="default" android:id="@+id/default_radioButton" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <RadioButton android:text="private" android:id="@+id/private_radioButton" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <RadioButton android:text="readable" android:id="@+id/readable_radioButton" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <RadioButton android:text="writable" android:id="@+id/writable_radioButton" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RadioGroup> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <CheckBox android:id="@+id/rem_checkBox" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:text="保存登陆信息" /> <Button android:id="@+id/saveBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:text="保存" /> </RelativeLayout> </LinearLayout>
import java.util.HashMap; import android.app.Activity; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.RadioGroup; import android.widget.Toast; import com.itxushuai.login.service.LoginService; public class MainActivity extends Activity implements OnClickListener{ private static final String TAG = "MainActivity"; private EditText username_et; private Button saveBtn; private EditText password_et ; private CheckBox rem_checkBox ; private RadioGroup radioGroup_id ; private boolean show = false; //当Activity被创建的时候调用 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //根据ID获取各个组件 saveBtn = (Button) findViewById(R.id.saveBtn); username_et = (EditText) findViewById(R.id.username_et); password_et = (EditText) findViewById(R.id.password_et); rem_checkBox = (CheckBox) findViewById(R.id.rem_checkBox); radioGroup_id = (RadioGroup) findViewById(R.id.radioGroup_id); //调用回显用户信息的方法 showData(); //为保存按钮设置事件监听 saveBtn.setOnClickListener(this); } //回显用户信息的方法 public void showData(){ //模拟从数据库中查找用户数据,并回显,由于原来数据库(这里是文件)中没有用户的信息,所以这第一次使用的时候会出现NullPointerException, //所以这里设置一个标志,当存入数据的时候,设置为true if(show){ HashMap<String,String> map = (HashMap<String, String>) LoginService.readInfoFromFile2(this); String username = map.get("username"); String password = map.get("password"); username_et.setText(username); password_et.setText(password); rem_checkBox.setChecked(true); } } //当用户点击按钮的时候执行 @Override public void onClick(View v) { //获取文本框中的内容 String username = username_et.getText().toString().trim(); String password = password_et.getText().toString().trim(); Log.i(TAG,"onclick.........."); boolean result = false;//设置一个boolean类型的值,表示保存是否成功 //对用户名和密码进行简单的合理性判断 if(TextUtils.isEmpty(username)||TextUtils.isEmpty(password)){ Toast.makeText(this, "用户名或密码不能为空", Toast.LENGTH_LONG).show();//用户名和密码不能为null return; }else{ //如果用户勾选了保存登陆信息按钮就将登陆信息存入文件中 if(rem_checkBox.isChecked()){ Log.i(TAG,"保存用户名和密码"); int rg_id = radioGroup_id.getCheckedRadioButtonId(); //对文件进行保存 if(v.getId() == R.id.saveBtn){ result = LoginService.saveInfoToFile(this,username,password); //result = LoginService.saveInfoToSD(this,username,password);//将文件存入SD卡 show = true; //已经保存了数据,将回显标志设为true,以便在第二次登陆的时候显示用户信息 } //写入不同模式的文件,为演示做准备 switch(rg_id){ case R.id.default_radioButton: result = LoginService.saveInfoToFile(this,username, password); break; case R.id.private_radioButton: result = LoginService.saveInfoToPrivateFile(this, username, password); break; case R.id.readable_radioButton: result = LoginService.saveInfoToReadableFile(this, username, password); break; case R.id.writable_radioButton: result = LoginService.saveInfoToWritableFile(this, username, password); break; } //保存成功,Toast一下 if(result){ Toast.makeText(this, "保存成功", Toast.LENGTH_LONG).show(); }else{ Toast.makeText(this, "保存失败", Toast.LENGTH_LONG).show(); } //这里是对数据库中的用户名和密码获取并进行验证,此处略去 // .............. } } } }
业务类:提供四种文件模式以及SD卡的写入
package com.itxushuai.login.service; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; import android.content.Context; import android.graphics.AvoidXfermode.Mode; import android.os.Environment; import android.util.Log; import android.widget.Toast; public class LoginService { private static final String TAG = null; /** * 保存用户名密码到手机里面的文件(默认模式:PRIVATE) * * @param context 上下文 提供一些信息 提供一些环境 帮助类 * @param username 用户名 * @param password 密码 * @return 是否保存成功 */ public static boolean saveInfoToFile(Context context, String username, String password){ try { File parentfile = context.getFilesDir();// /data/data/com.itxushuai.login/files File des = new File(parentfile,"info.txt");// /data/data/com.itxushuai.login/files/info.txt FileOutputStream fos = new FileOutputStream(des); String info = username+"&"+password; fos.write(info.getBytes()); fos.close(); return true ; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将用户名密码保存到私有模式的文件中 */ public static boolean saveInfoToPrivateFile(Context context, String username, String password){ try{ FileOutputStream fos = context.openFileOutput("private.txt",Context.MODE_PRIVATE); String info = username+"&"+password; fos.write(info.getBytes()); fos.close(); return true ; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将用户名密码到可读模式的文件中 */ public static boolean saveInfoToReadableFile(Context context, String username, String password){ try { Log.i(TAG,"saveInfoToReadableFile"); FileOutputStream fos = context.openFileOutput("readable.txt",Context.MODE_WORLD_READABLE); String info = username+"&"+password; fos.write(info.getBytes()); fos.close(); return true ; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将用户名密码到可写模式的文件中 */ public static boolean saveInfoToWritableFile(Context context, String username, String password){ try { FileOutputStream fos = context.openFileOutput("writable.txt",Context.MODE_WORLD_WRITEABLE); String info = username+"&"+password; fos.write(info.getBytes()); fos.close(); return true ; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将用户名密码到可读可写模式的文件中 */ public static boolean saveInfoToPublicFile(Context context, String username, String password){ try { FileOutputStream fos = context.openFileOutput("public.txt",Context.MODE_WORLD_WRITEABLE+Context.MODE_WORLD_WRITEABLE); String info = username+"&"+password; fos.write(info.getBytes()); fos.close(); return true ; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将用户名密码到SD卡中 */ public static boolean saveInfoToSD(Context context,String username,String password){ try { //判断SD卡是否存在 if(Environment.MEDIA_MOUNTED.equals(Environment. getExternalStorageState())){ //获取SD卡的路径并创建一个目的文件 File sdFile = new File(Environment.getExternalStorageDirectory(),"sdFile"); FileOutputStream fos = new FileOutputStream(sdFile); fos.write((username+"&"+password).getBytes()); fos.close(); return true; }else { Toast.makeText(context, "sd卡不存在", Toast.LENGTH_SHORT).show(); return false; }}catch (Exception e) { e.printStackTrace(); return false; } } /** * 获取保存在文件里面的用户名 和密码:context.getFilesDir() * @param context * @return */ public static Map readInfoFromFile(Context context){ try { File parentfile = context.getFilesDir(); File srcFile = new File(parentfile,"private.txt"); FileInputStream fis = new FileInputStream(srcFile); BufferedReader bis = new BufferedReader(new InputStreamReader(fis)); String result = bis.readLine(); String username = result.split("&")[0]; String password = result.split("&")[1]; Map<String,String> map = new HashMap<String,String>(); map.put("username", username); map.put("password", password); bis.close(); return map; } catch (Exception e) { e.printStackTrace(); return null; } } /** * 获取保存在文件里面的用户名 和密码: context.openFileInput("info.txt"); */ public static Map readInfoFromFile2(Context context){ try { FileInputStream fileInStream = context.openFileInput("info.txt"); BufferedReader bis = new BufferedReader(new InputStreamReader(fileInStream)); String result = bis.readLine(); String username = result.split("&")[0]; String password = result.split("&")[1]; Map<String,String> map = new HashMap<String,String>(); map.put("username", username); map.put("password", password); bis.close(); return map; } catch (Exception e) { e.printStackTrace(); return null; } } }
OtherActivity:演示在一个应用中读取另外一个应用中的文件
布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity" > <Button android:id="@+id/default_id" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="读默认文件" /> <Button android:id="@+id/private_id" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="读私有文件" /> <Button android:id="@+id/readable_id" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="读可读文件" /> <Button android:id="@+id/writatble_id" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="读可写文件" /> <Button android:id="@+id/read_and_writatble_id" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="读可读可写文件" /> </LinearLayout>
MainActivity
package com.itxushuai.other; import com.itxushuai.service.ReadFile; import android.os.Bundle; import android.app.Activity; import android.util.Log; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity implements OnClickListener{ private static final String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button defaultBtn = (Button) findViewById(R.id.default_id); Button privateBtn = (Button) findViewById(R.id.private_id); Button readableBtn = (Button) findViewById(R.id.readable_id); Button writeBtn = (Button) findViewById(R.id.writatble_id); Button read_and_writatbleBtn= (Button) findViewById(R.id.read_and_writatble_id); defaultBtn.setOnClickListener(this); privateBtn.setOnClickListener(this); readableBtn.setOnClickListener(this); writeBtn.setOnClickListener(this); read_and_writatbleBtn.setOnClickListener(this); } @Override public void onClick(View v) { switch(v.getId()){ case R.id.default_id: ReadFile.readDefaultFile(this); break; case R.id.private_id: ReadFile.readPrivateFile(this); break; case R.id.readable_id: ReadFile.readReadableFile(this); break; case R.id.writatble_id: ReadFile.readWritableFile(this); break; case R.id.read_and_writatble_id: ReadFile.readPublicFile(this); break; } } }
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import android.content.Context; import android.util.Log; import android.widget.Toast; public class ReadFile { private static final String TAG = "ReadFile"; //读取缺省模式的文件 public static void readDefaultFile(Context context){ File file = new File("/data/data/com.itxushuai.login/files/info.txt"); Log.i(TAG, "readDefaultFile............"); FileInputStream fis; try { fis = new FileInputStream(file); BufferedReader bufr = new BufferedReader(new InputStreamReader(fis)); String msg = bufr.readLine(); bufr.close(); Toast.makeText(context, msg, 0).show(); } catch (Exception e) { e.printStackTrace(); } } //读取私有模式的文件 public static void readPrivateFile(Context context){ File file = new File("/data/data/com.itxushuai.login/files/private.txt"); Log.i(TAG, "readPrivateFile............"); FileInputStream fis; try { fis = new FileInputStream(file); BufferedReader bufr = new BufferedReader(new InputStreamReader(fis)); String msg = bufr.readLine(); bufr.close(); Toast.makeText(context, msg, 0).show(); } catch (Exception e) { e.printStackTrace(); } } //读取可读模式的文件 public static void readReadableFile(Context context){ Log.i(TAG, "readReadableFile............"); File file = new File("/data/data/com.itxushuai.login/files/readable.txt"); FileInputStream fis; try { fis = new FileInputStream(file); BufferedReader bufr = new BufferedReader(new InputStreamReader(fis)); String msg = bufr.readLine(); bufr.close(); Toast.makeText(context, msg, 0).show(); } catch (Exception e) { e.printStackTrace(); } } //读取可写模式的文件 public static void readWritableFile(Context context){ Log.i(TAG, "readWritableFile............"); File file = new File("/data/data/com.itxushuai.login/files/writable.txt"); FileInputStream fis; try { fis = new FileInputStream(file); BufferedReader bufr = new BufferedReader(new InputStreamReader(fis)); String msg = bufr.readLine(); bufr.close(); Toast.makeText(context, msg, 0).show(); } catch (Exception e) { e.printStackTrace(); } } }
读取各种模式文件时Logcat捕捉的信息: