数据存储一:临时存储和文件存储 实验目的 1.了解Android数据存储的基本方法 2.掌握SharedPreferences、内部文件存储、外部存储的技术 实验内容: (1)尝试使用SharedPreferences在程序关闭时保存用户输入的信息,并在程序重新启动时自动恢复这些信息。(2)以INI文件的形式,将数据保存在内部或外部存储器上,实现相同的功能 实验原理:
一、SharedPreferences 1、SharedPreferences 简介 SharedPreferences是一种轻量级的永久性的数据保存方式。通过SharedPreferences开发人员可以将NVP(Name/Value Pair,名称/值对)保存在Android内部存储器的文件系统中,而不需关心文件系统的操作过程。 一般用于:保存应用程序的配置信息和个性化内容。 也可用于:不同应用程序间的数据共享。
2、SharedPreferences支持三种访问模式 私有(MODE_PRIVATE):仅创建SharedPreferences的程序有权限对其进行读取或写入 全局读(MODE_WORLD_READABLE):不仅创建程序可以对其进行读取或写入,其它应用程序也具有读取操作的权限,但没有写入操作的权限 全局写(MODE_WORLD_WRITEABLE):所有程序都可以对其进行写入操作,但没有读取操作的权限
3、使用过程 1)定义常量 1 2 3 4 public static int MODE = MODE_PRIVATE;public static final String PREFERENCE_NAME = "SaveSetting" ;
2)往SharedPreferences中写数据 1 2 3 4 5 6 7 8 SharedPreferences sharedPreferences = getSharedPreferences(PREFERENCE_NAME, MODE); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putString("Name" , "Tom" ); editor.putInt("Age" , 20 ); editor.putFloat("Height" , 1.81f ); editor.commit();
3)从SharedPreferences中读数据 1 2 3 4 5 6 SharedPreferences sharedPreferences = getSharedPreferences(PREFERENCE_NAME, MODE); String name = sharedPreferences.getString("Name" ,"Default Name" ); int age = sharedPreferences.getInt("Age" , 20 ); float height = sharedPreferences.getFloat("Height" ,1.81f );
4、查看SharedPreferences文件 通过eclipse 的菜单window->show view-> other->android->file explorer可以查看模拟器上的文件。 SharedPreferences产生的文件就保存在/data/data//shared_prefs目录下 选中文件,点击右上角:pull a file from a device可另存该文件。
二、内部存储:直接使用文件保存数据 1、简介 Android系统允许应用程序创建仅能够自身访问的私有文件,文件保存在设备的内部存储器上,即Android系统下的/data/data//files目录中 可通过文件访问权限的控制保证文件的私密性 四种文件操作模式
模式
说明
MODE_PRIVATE
私有模式,文件仅能被创建文件的程序访问,或具有相同UID的程序访问。
MODE_APPEND
追加模式,如果文件已经存在,则在文件的结尾处添加新数据。
MODE_WORLD_READABLE
全局读模式,允许任何程序读取私有文件。
MODE_WORLD_WRITEABLE
全局写模式,允许任何程序写入私有文件。
因为流文件操作可能会遇到各种问题而最终导致操作失败,在实际操作过程中会遇到错误提示,因此代码应该使用try/catch捕获可能产生的异常
2、文件输出基本过程:将字符串写入文件,文件作为输出 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 FileOutputStream fos = null ; try { fos = openFileOutput(fileName,Context.MODE_PRIVATE); fos.write(text.getBytes()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) {e.printStackTrace(); } finally { if (fos != null ){ try { fos.flush(); fos.close(); } catch (IOException e) { e.printStackTrace(); } } }
说明: 1)行3中fileName不可以包含描述路径的斜杠 2)调用close()之前务必调用flush()将缓冲中的所有数据写入文件 3)openFileOutput打开应用的私有文件,如果文件不存在则创建。 4)FileOutputStream是写到文件的字节流
3、文件输入基本过程:读取文件内容到字符串,文件作为输入 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 FileInputStream fis = null ; try { fis = openFileInput(fileName); if (fis.available() == 0 ){ return ; } byte [] readBytes = new byte [fis.available()]; while (fis.read(readBytes) != -1 ); String text = new String(readBytes); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (fis != null ){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } }
说明: 1)FileInputStream 的方法available() 返回估计可读的字节数. 2)public int read (byte[] buffer, int byteOffset, int byteCount) 最多从字节流中读byteCount个字节,并存储在字节数组缓冲buffer中,存放时放在byteOffset指定的在buffer的位置。返回实际读的字节数,或者如果读到流的末尾了就返回-1. 运行程序后,在文件浏览器中可查看:
导出输出的流文件,可查看内容。 另外,注意只有当应用在模拟器上运行起来后,才能使用File Explore看到保存的文件。
三、外部存储 1、外部存储应用场合 Micro SD卡适用于保存大尺寸的文件或者是一些无需设置访问权限的文件 如果用户希望保存录制的视频文件和音频文件,因为Android设备的内部存储空间有限,所以使用Micro SD卡则是非常适合的选择 但如果需要设置文件的访问权限,则不能够使用Micro SD卡,因为Micro SD卡使用FAT(File Allocation Table)文件系统,不支持访问模式和权限控制
2、使用外部存储的前提条件 正确加载SD卡后,SD卡中的目录和文件被映射到/mnt/sdcard目录下 因为用户可以加载或卸载SD卡,所以在编程访问SD卡前首先需要检测/mnt/sdcard目录是否可用 如果不可用,说明设备中的SD卡已经被卸载。如果可用,则直接通过使用标准的java.io.File类进行访问
3、编码时与内部存储的区别 1.与内部存储的核心代码比较相似,不同之处在于代码中添加了/mnt/sdcard目录存在性检查,并使用“绝对目录+文件名”的形式表示新建立的文件,并在写入文件前对文件的存在性和可写入性进行检查 4、程序运行时,若发生“SD 卡不存在或不可写”的错误, 1)检查是否在manifest.xml文件中增加使用许可; 1 2 <uses-permission android:name ="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" > </uses-permission > <uses-permission android:name ="android.permission.WRITE_EXTERNAL_STORAGE" > </uses-permission >
2)检查模拟器中对SD卡的设置是否正确,比如,需要设置SD卡的存储容量。 实验步骤: 要求: 1)可以参考教材上的例子,但一定不要直接拷贝; 2)将实验代码和运行效果截图放在实验报告中提交。
1.使用SharedPreferences保存用户输入的信息 1)建立一个项目“SharedPreferencesDemo” 2)自行设计该应用的用户界面(注意:在界面里要有接受用户输入的控件,比如,可以设计一个“设置”Activity,用户打开这个Activity时,从配置文件里读取用户设置,当用户修改设置后将更改后的设置保存到配置文件中),参考界面如下:
3)为用户界面添加事件处理函数,在适当的事件里添加读取和保存配置文件的代码。
2.以INI文件的形式,将数据保存在内部或外部存储器上,实现相同的功能 1)建立一个项目“FileStoreDemo” 2)用户界面可以与前面相同 3)可使用内部存储或外部存储保存配置到ini文件(字段格式自定),可参考”实验原理”部分内容实现。
程序一(使用SharedPreferences保存用户输入的信息)源代码 ActivityA.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 package com.self.user.sharedpreferencesdemo;import android.content.Context;import android.content.Intent;import android.content.SharedPreferences;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.text.TextUtils;import android.view.View;import android.widget.Button;import android.widget.EditText;public class ActivityA extends AppCompatActivity { public static SharedPreferences preferences; public static final String PREF_NAME = "MyApp_pref" ; private EditText et_username = null ; private EditText et_password = null ; private Button loginBtn = null ; String enteredUsername = "" , enteredPassword = "" ; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_a); preferences = getApplicationContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); et_username = findViewById(R.id.et_userName); et_password = findViewById(R.id.et_password); loginBtn = findViewById(R.id.login_button); if (existingUser()) { startActivity(new Intent(ActivityA.this , ActivityB.class)); finish(); } loginBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick (View v) { if (isValid()) { AppSharedPreferences.setPreference(getApplicationContext(), AppSharedPreferences.Pref_UserName, enteredUsername); AppSharedPreferences.setPreference(getApplicationContext(), AppSharedPreferences.Pref_Password, enteredPassword); startActivity(new Intent(ActivityA.this , ActivityB.class)); finish(); } } }); } private boolean isValid () { enteredUsername = et_username.getText().toString(); enteredPassword = et_password.getText().toString(); if (TextUtils.isEmpty(enteredUsername)) { et_username.setError("Please enter a username" ); et_username.requestFocus(); return false ; } else if (TextUtils.isEmpty(enteredPassword)) { et_password.setError("Please enter a password" ); et_password.requestFocus(); return false ; } return true ; } private boolean existingUser () { return !TextUtils.isEmpty(AppSharedPreferences.getPreferences(getApplicationContext(), AppSharedPreferences.Pref_UserName)); } }
ActivityB.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 package com.self.user.sharedpreferencesdemo;import android.content.Context;import android.content.Intent;import android.content.SharedPreferences;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.text.TextUtils;import android.view.View;import android.widget.Button;import android.widget.EditText;public class ActivityA extends AppCompatActivity { public static SharedPreferences preferences; public static final String PREF_NAME = "MyApp_pref" ; private EditText et_username = null ; private EditText et_password = null ; private Button loginBtn = null ; String enteredUsername = "" , enteredPassword = "" ; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_a); preferences = getApplicationContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); et_username = findViewById(R.id.et_userName); et_password = findViewById(R.id.et_password); loginBtn = findViewById(R.id.login_button); if (existingUser()) { startActivity(new Intent(ActivityA.this , ActivityB.class)); finish(); } loginBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick (View v) { if (isValid()) { AppSharedPreferences.setPreference(getApplicationContext(), AppSharedPreferences.Pref_UserName, enteredUsername); AppSharedPreferences.setPreference(getApplicationContext(), AppSharedPreferences.Pref_Password, enteredPassword); startActivity(new Intent(ActivityA.this , ActivityB.class)); finish(); } } }); } private boolean isValid () { enteredUsername = et_username.getText().toString(); enteredPassword = et_password.getText().toString(); if (TextUtils.isEmpty(enteredUsername)) { et_username.setError("Please enter a username" ); et_username.requestFocus(); return false ; } else if (TextUtils.isEmpty(enteredPassword)) { et_password.setError("Please enter a password" ); et_password.requestFocus(); return false ; } return true ; } private boolean existingUser () { return !TextUtils.isEmpty(AppSharedPreferences.getPreferences(getApplicationContext(), AppSharedPreferences.Pref_UserName)); } }
AppSharedPreferences.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 package com.self.user.sharedpreferencesdemo;import android.content.Context;import android.content.SharedPreferences;public class AppSharedPreferences { public static final String Pref_UserName = "UserName" ; public static final String Pref_Password = "Password" ; public static void setPreference (Context context, String key, String value) { SharedPreferences.Editor editor = ActivityA.preferences.edit(); editor.putString(key, value); editor.apply(); } public static String getPreferences (Context context, String key) { return ActivityA.preferences.getString(key, "" ); } public static void setBooleanPreferences (Context context, String key, boolean value) { SharedPreferences.Editor mSharedPrefsEditor = ActivityA.preferences.edit(); mSharedPrefsEditor.putBoolean(key, value); mSharedPrefsEditor.apply(); } public static boolean getBooleanPreferences (Context context, String key) { return ActivityA.preferences.getBoolean(key, false ); } public static void clearPreference (Context context) { SharedPreferences.Editor editor = ActivityA.preferences.edit(); editor.clear(); editor.apply(); } public static boolean removeKeyValue (Context context, String key) { SharedPreferences.Editor editor = ActivityA.preferences.edit(); editor.remove(key); editor.apply(); return true ; } }
activity_a.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 <?xml version="1.0" encoding="utf-8"?> <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" android:padding ="20dp" tools:context =".ActivityA" > <EditText android:id ="@+id/et_userName" android:layout_width ="match_parent" android:layout_height ="wrap_content" android:layout_marginTop ="50dp" android:hint ="Username" android:imeOptions ="actionNext" android:inputType ="text" android:maxLength ="15" android:maxLines ="1" android:text ="" android:textColor ="@android:color/black" android:textSize ="16sp" tools:ignore ="HardcodedText" /> <EditText android:id ="@+id/et_password" android:layout_width ="match_parent" android:layout_height ="wrap_content" android:layout_marginTop ="20dp" android:hint ="Password" android:imeOptions ="actionDone" android:inputType ="textPassword" android:maxLength ="15" android:maxLines ="1" android:text ="" android:textColor ="@android:color/black" android:textSize ="16sp" tools:ignore ="HardcodedText" /> <Button android:id ="@+id/login_button" android:layout_width ="match_parent" android:layout_height ="wrap_content" android:layout_marginTop ="50dp" android:background ="@color/colorPrimary" android:text ="Login" android:textColor ="@android:color/white" android:textSize ="20sp" tools:ignore ="HardcodedText" /> </LinearLayout >
activity_b.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <?xml version="1.0" encoding="utf-8"?> <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" android:gravity ="center" android:padding ="20dp" tools:context =".ActivityB" > <TextView android:id ="@+id/tv_greeting" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:gravity ="center" android:layout_gravity ="center_horizontal" android:text ="Welcome" android:textColor ="@android:color/black" android:textSize ="25sp" tools:ignore ="HardcodedText" /> <Button android:id ="@+id/logout_button" android:layout_width ="match_parent" android:layout_height ="wrap_content" android:layout_margin ="50dp" android:background ="@color/colorPrimary" android:text ="Logout" android:textColor ="@android:color/white" android:textSize ="20sp" tools:ignore ="HardcodedText" /> </LinearLayout >
程序一(使用SharedPreferences保存用户输入的信息)功能简介 密码检查模块(与实验五相同)不再说明
案例一: 登陆前
登陆后,保留账号信息并且显示欢迎界面
案例二: 登陆前
登陆后,保留账号信息并且显示欢迎界面
文件内容
程序二(以INI文件的形式/内部存储)源代码 MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 package com.codeteenageer.filestoredemo;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.EditText;import android.widget.TextView;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStreamWriter;public class MainActivity extends AppCompatActivity { private EditText et; private TextView tv; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); et = (EditText) findViewById(R.id.et); tv = (TextView) findViewById(R.id.tv); } public void save (View view) { save(et.getText().toString()); } public void get (View view) { tv.setText(getData()); } private void save (String data) { FileOutputStream out = null ; BufferedWriter writer = null ; try { out = openFileOutput("data.ini" , MODE_PRIVATE); writer = new BufferedWriter(new OutputStreamWriter(out)); writer.write(data); } catch (IOException e) { e.printStackTrace(); } finally { try { if (writer != null ) { writer.close(); } } catch (IOException e) { e.printStackTrace(); } } } private String getData () { FileInputStream in = null ; BufferedReader reader = null ; StringBuilder content = new StringBuilder(); try { in = openFileInput("data.ini" ); reader = new BufferedReader(new InputStreamReader(in)); String line = "" ; while ((line = reader.readLine()) != null ) { content.append(line); } } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null ) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } return content.toString(); } }
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android" xmlns:app ="http://schemas.android.com/apk/res-auto" xmlns:tools ="http://schemas.android.com/tools" android:layout_width ="match_parent" android:layout_height ="match_parent" android:orientation ="vertical" tools:context ="com.codeteenageer.filestoredemo.MainActivity" > <EditText android:id ="@+id/et" android:layout_width ="match_parent" android:layout_height ="wrap_content" /> <Button android:layout_width ="match_parent" android:layout_height ="wrap_content" android:onClick ="save" android:text ="保存" /> <TextView android:id ="@+id/tv" android:layout_width ="match_parent" android:layout_height ="wrap_content" android:text ="数据显示" /> <Button android:layout_width ="match_parent" android:layout_height ="wrap_content" android:onClick ="get" android:text ="获取" /> </LinearLayout >
程序二(以INI文件的形式/内部存储)功能简介 点击保存,后自动保存到ini文件 获取即显示数字
ini文件
程序三(以INI文件的形式/外部存储)源代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 package org.crazyit.io;import android.app.Activity;import android.os.Bundle;import android.os.Environment;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.InputStreamReader;import java.io.RandomAccessFile;public class MainActivity extends Activity { final String FILE_NAME = "/zyh.ini" ; @Override public void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.main); Button read = (Button) findViewById(R.id.read); Button write = (Button) findViewById(R.id.write); final EditText edit1 = (EditText) findViewById(R.id.edit1); final EditText edit2 = (EditText) findViewById(R.id.edit2); write.setOnClickListener(new OnClickListener() { @Override public void onClick (View source) { write(edit1.getText().toString()); edit1.setText("" ); } }); read.setOnClickListener(new OnClickListener() { @Override public void onClick (View v) { edit2.setText(read()); } }); } private String read () { try { if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { File sdCardDir = Environment.getExternalStorageDirectory(); System.out.println("----------------" + sdCardDir); FileInputStream fis = new FileInputStream( sdCardDir.getCanonicalPath() + FILE_NAME); BufferedReader br = new BufferedReader(new InputStreamReader(fis)); StringBuilder sb = new StringBuilder("" ); String line = null ; while ((line = br.readLine()) != null ) { sb.append(line); } br.close(); return sb.toString(); } } catch (Exception e) { e.printStackTrace(); } return null ; } private void write (String content) { try { if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { File sdCardDir = Environment.getExternalStorageDirectory(); File targetFile = new File(sdCardDir .getCanonicalPath() + FILE_NAME); RandomAccessFile raf = new RandomAccessFile( targetFile, "rw" ); raf.seek(targetFile.length()); raf.write(content.getBytes()); raf.close(); } } catch (Exception e) { e.printStackTrace(); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <?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" > <EditText android:id ="@+id/edit1" android:layout_width ="match_parent" android:layout_height ="wrap_content" android:lines ="4" /> <Button android:id ="@+id/write" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:text ="@string/write" /> <EditText android:id ="@+id/edit2" android:layout_width ="match_parent" android:layout_height ="wrap_content" android:cursorVisible ="false" android:lines ="4" /> <Button android:id ="@+id/read" android:layout_width ="wrap_content" android:layout_height ="wrap_content" android:text ="@string/read" /> </LinearLayout >
程序三(以INI文件的形式/外部存储)功能简介 输入文本,保存,读取,设置为wr,往文件后面继续写
文件位置
本文使用 CC BY-NC-SA 3.0 中国大陆 协议许可 具体请参见 知识共享协议 本文链接: https://zyhang8.github.io/2019/11/01/android-exp6/