在安卓里面,获取数据的方式有两种,第一种就是我们之前所讲的网络获取,第二种就是我们接下来要讲的本地获取数据,本地获取的方式有通过文件获取,SharedPreferences(简称sp),sqlite数据库获取 三种方法 ,本质上来说,我们在网络获取的数据通常情况下也会缓存一份到本地,打个比方说,你打开网络听一首新歌,关闭网络以后,你会发现歌曲会一直播放到它缓存好的进度,缓存到的位置在文件,sp,sqlite都有可能。接下来我会一个一个来讲述
在安卓里面有几个地方可以存文件数据,第一个是可以存在我们的工程里面,工程里面有两个路径,第一个就是raw目录,第二个是asserts目录,这两个工程目录会放到我们应用包里面,
创建方式
我们先创建一个raw目录,我们再创建一个文本文件把
第一步,新建file
命名,选择格式,ok
我们先在这个文件写入文本
activity代码
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InputStream inputStream = null;
Reader reader = null;
BufferedReader bufferedReader = null;
try {
//得到资源中的Raw数据流
inputStream = getResources().openRawResource(R.raw.test);
reader = new InputStreamReader(inputStream);// 字符流
bufferedReader = new BufferedReader(reader); //缓存流
StringBuilder result = new StringBuilder();
String temp;
while ((temp = bufferedReader.readLine()) != null) {
result.append(temp);
}
Log.i("MainActivity", "result:" + result);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
//得到资源中的assets数据流
inputStream = getResources().getAssets().open("test");
该目录存放文件类型规则如下:
路径 | 功能 |
---|---|
data/data/包名/shared_ prefs | 存放SharedPreferences数据 |
data/data/包名/ databases | 存放数据库数据 |
data/data/包名/files | 存放普通数据 |
data/data/包名/cache | 存放缓存文件 |
activity代码
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FileOutputStream fileOutputStream = null;
try {
String text = "hello world";
fileOutputStream = openFileOutput("test.txt", MODE_PRIVATE);
fileOutputStream.write(text.getBytes());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
运行,会发现data/data/包名目录下多了一个文件
openFileOutput方法参数详解
@Override
//name表示存储文件名字 mode表示存储方式
public FileOutputStream openFileOutput(String name, int mode)
throws FileNotFoundException {
}
mode参数值 | 参数含义 |
---|---|
Context.MODE_PRIVATE | 指定该文件数据只能被本应用程序读、写 |
Context.MODE_WORLD_READABLE | 指定该文件数据能被其他应用程序读,但不能写 |
Context.MODE_WORLD_WRITEABLE | 指定该文件数据能被其他应用程序读 |
Context.MODE_APPEND | 该模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件 |
指定路径,再往里面写数据
String text = "hello world";//文件内容
File file1=new File("/data/data/com.c201801020224.myapplication/databases","test.txt");//指定路径
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(file1);
fileOutputStream.write(text.getBytes());
} catch (Exception e) {
e.printStackTrace();
}finally {
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
activity代码
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FileInputStream fileInputStream = null;
Reader reader = null;
BufferedReader bufferedReader = null;
try {
fileInputStream = openFileInput("test.txt");
reader = new InputStreamReader(fileInputStream);// 字符流
bufferedReader = new BufferedReader(reader); //缓冲流
StringBuilder result = new StringBuilder();
String temp;
while ((temp = bufferedReader.readLine()) != null) {
result.append(temp);
}
Log.i("MainActivity", "result:" + result);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
activity代码
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InputStream inputStream = null;
Reader reader = null;
BufferedReader bufferedReader = null;
try {
File file=new File("/data/data/com.c201801020224.myapplication/files", "test.txt");
inputStream = new FileInputStream(file);
reader = new InputStreamReader(inputStream);
bufferedReader = new BufferedReader(reader);
StringBuilder result = new StringBuilder();
String temp;
while ((temp = bufferedReader.readLine()) != null) {
result.append(temp);
}
Log.i("MainActivity", "result:" + result);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
如果是对sd卡进行读写,必须要申请动态权限
首先,我们要先到mainifests里面添加权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
如果是 AndroidQ 或者更高的版本还需要在 manifest.xml 文件中的 application 节点下加入
android:requestLegacyExternalStorage="true"
checkPermission();
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.WRITE_EXTERNAL_STORAGE"};
private void checkPermission() {
//检查权限(NEED_PERMISSION)是否被授权 PackageManager.PERMISSION_GRANTED表示同意授权
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission
.WRITE_EXTERNAL_STORAGE)) {
Toast.makeText(this, "请开通相关权限,否则无法正常使用本应用!",
Toast.LENGTH_SHORT).show();
}
//申请权限
ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
} else {
Toast.makeText(this, "已授权成功!", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_EXTERNAL_STORAGE: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "授权成功!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "授权被拒绝!", Toast.LENGTH_SHORT).show();
}
return;
}
}
}
补充:为什么读取SD卡需要动态申请权限呢? 是因为在sd卡里面有很多我们个人隐私的文件,比如相册,如果允许权限了,那么就可以读到我们相册里面的所有照片,比如还有读地理位置,读短信,所以在Android6.0以后,对于这一类带有“危险”操作的权限,是需要动态申请权限的,由用户来选择是否允许
添加 writeSdcard() 方法代码
private void writeSdcard() {
String text = "hello world";
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
File storage = Environment.getExternalStorageDirectory();
File tmepfile = new File(storage.getPath());
if (! tmepfile.exists()) {
tmepfile.mkdirs();
}
File file1=new File(tmepfile,"test.txt");
if (!file1.exists()){
try {
file1.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(file1);
fileOutputStream.write(text.getBytes());
} catch (Exception e) {
e.printStackTrace();
}finally {
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
运行
添加代码
private void readSdcard() {
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
InputStream inputStream = null;
Reader reader = null;
BufferedReader bufferedReader = null;
try {
File storage = Environment.getExternalStorageDirectory();
File tmepfile = new File(storage.getPath());
File file=new File(tmepfile, "test.txt");
inputStream = new FileInputStream(file);
reader = new InputStreamReader(inputStream);
bufferedReader = new BufferedReader(reader);
StringBuilder result = new StringBuilder();
String temp;
while ((temp = bufferedReader.readLine()) != null) {
result.append(temp);
}
Log.i("MainActivity", "result:" + result);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
实际上sp数据也是存在data/data/包名下面,他会创建一个特殊类型的文件,然后再往里面写
SharedPreferences是Android平台上-个轻量级的存储辅助类,用来保存应用的一些常用配置,它提供了string,set, int, long, float, boolean六种数据类型。最终数据是以xm1形式进行存储。在应用中通常做一些简单数据的持久化缓存。
sp比较特殊的地方在于,它不是以一种txt的形式存储,他是以xml的形式来存储,我们之前将网络请求的时候就有讲到xml的形式来传输数据,只是因为后来json的流行,所以xml就逐渐被淘汰了,那么在安卓里面,xml本地存储还没有被淘汰,而SharedPreferences本质上就是一种xml的形式来存储,存储的方式可以来存一些安卓的基本类型, int, long, float, boolean类型,也包括string,set类型,
下面举一个sp应用的场景
比如说在我们qq登录的时候,第一次登录成功了,第二次就会直接进入主界面了,不会再进到登录界面,实际上当我们第一次登录成功的时候,系统会把我们登陆的状态,可以用一个boolean类型的值保存到本地,登陆成功就可以保存为ture,保存到本地的形式可以用我们上述讲到的文件,但是文件存储可能还要对里面的信息进行解析,我们这里就有这么一种更加方便的方式就是接下来所要讲到的sp,sp主要是来存储这种少量的数据
,而且优势就是sp读写起来会比文件更加方便,所以像这种情况我们就可以用sp的形式来存储
我们先把之前的方法代码都删掉,因为sp是存储在data/data/包名目录下的,所以我们不需要动态申请权限,
第一步,我们先加一个button
然后再给按钮添加点击事件
Button button=findViewById(R.id.button);//实例化 拿到控件的引用
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
activity代码(拿到SharedPreferences,再添加数据)
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button=findViewById(R.id.button);//实例化 拿到控件的引用
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences sharedPreferences=getSharedPreferences("user",MODE_PRIVATE);//拿到 sharedPreferences 的引用 MODE_PRIVATE表示只能被本应用读写,不能被其他应用读写
SharedPreferences.Editor editor=sharedPreferences.edit();//拿到编辑对象
editor.putBoolean("isLogin",true);//添加数据
editor.commit();
}
});
}
}
运行,点击按钮,刷新一下data/data/包名目录,会发现我们的数据被保存到了一个文件夹
代码
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button=findViewById(R.id.button);//实例化 拿到控件的引用
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences sharedPreferences=getSharedPreferences("user",MODE_PRIVATE);//拿到 sharedPreferences 的引用 MODE_PRIVATE表示只能被本应用读写,不能被其他应用读写
boolean isLogin = sharedPreferences.getBoolean("isLogin", false);//当key不存在时,默认返回defValue的值
Log.i("Main","isLogin "+isLogin);
}
});
}
}
运行(打印成功)
关于SharedPreferences和文件存储就讲到这里啦,谢谢您的阅读,下一讲我们主要讲数据库