目录
一、文件存储
文件存储分为内部存储和外部存储两种方式。
1、内部存储
内部存储是每个应用程序都有一个私有的内部存储空间,只有该应用本身可以访问。内部存储通常用于存储应用程序的私有数据,如数据库文件、SharedPreferences 文件等。这些文件默认存储在应用的内部存储目录中(该文件默认存储到data/data/<packagename>/目录下),其他应用无法直接访问。进行文件读写操作时,使用Context提供的openFileOutput()和openFileInput()方法,这两个方法返回FileOutputStream和FileInputStream对象
使用方法如下:
FileOutputStream os = openFileOutput(String name,int mode);
FileInputStream is = openFileInput(String name);
其中参数name:表示文件名
参数mode:表示文件的操作模式,有四种模式(如下表)。
模式 | 功能 |
MODE_PRIVATE | 该文件只能被当前程序读写 |
MODE_APPEND | 该文件的内容可以继续添加 |
MODE_WORLD_READABLE | 该文件的内容可以被其他程序读 |
MODE_WORLD_WRITEABLE | 该文件的内容可以被其他程序写 |
内部存储例子:
MainActivity:
package com.example.file_inward_demo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
public class MainActivity extends AppCompatActivity {
Button write_btn,read_btn;
TextView read_tv;
EditText write_ed;
FileOutputStream os;
FileInputStream is;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
write_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
writeFile(write_ed.getText().toString());
write_ed.setText("");
}
});
read_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
read_tv.setText(readFile());
}
});
}
private void initView() {
read_btn = findViewById(R.id.read_btn);
read_tv = findViewById(R.id.read_tv);
write_btn = findViewById(R.id.write_btn);
write_ed = findViewById(R.id.write_ed);
}
private void writeFile(String content){
try {
os = openFileOutput("data",MODE_APPEND);
os.write(content.getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (os != null)
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private String readFile(){
try {
is = openFileInput("data");
byte[] buffer = new byte[is.available()];
is.read(buffer);
String content = new String(buffer);
return content;
} catch (Exception e) {
e.printStackTrace();
return null;
}finally {
try {
if (is!=null)
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
activity_main:
<?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=".MainActivity">
<EditText
android:id="@+id/write_ed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入需要保存的内容:"
/>
<Button
android:id="@+id/write_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:text="写入文件"
android:layout_gravity="center"
/>
<TextView
android:id="@+id/read_tv"
android:layout_width="match_parent"
android:layout_height="350dp"
android:textSize="18sp"
/>
<Button
android:id="@+id/read_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="18sp"
android:text="读取文件"/>
</LinearLayout>
运行效果:
2、外部存储
外部存储是指将数据以文件的形式存储到手机的外部设备(文件通常位于mnt/sdcard目录下),比如sd卡。由于sd卡可能被移除,因此在使用sd卡存储时,首先判断是否可用(调用Environment.getExternalStorageState()方法来判断sd卡是否可用)。当外部设备有读权限时,那么就可以使用FileOutputStream和FileInputStream对象来进行读写文件操作。
动态申请权限:
ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE},1);@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if(requestCode == 1){ for (int i = 0; i < permissions.length; i++) { if(grantResults[i] == PackageManager.PERMISSION_GRANTED){ // 写文件 }else { Toast.makeText(this, "权限"+permissions[i]+"申请失败!!!", Toast.LENGTH_SHORT).show(); } } } }
外部存储例子:
MainActivity:
package com.example.file_outward_demo;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
public class MainActivity extends AppCompatActivity {
Button write_btn,read_btn;
TextView read_tv;
EditText write_ed;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE},1);
write_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
writeFile(write_ed.getText().toString());
write_ed.setText("");
}
});
read_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
read_tv.setText(readFile());
}
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode == 1){
for (int i = 0; i < permissions.length; i++) {
if(grantResults[i] == PackageManager.PERMISSION_GRANTED){
// 写文件
}else {
Toast.makeText(this, "权限"+permissions[i]+"申请失败!!!", Toast.LENGTH_SHORT).show();
}
}
}
}
private void initView() {
read_btn = findViewById(R.id.read_btn);
read_tv = findViewById(R.id.read_tv);
write_btn = findViewById(R.id.write_btn);
write_ed = findViewById(R.id.write_ed);
}
private void writeFile(String content){
String state = Environment.getExternalStorageState();
if (state.equals(Environment.MEDIA_MOUNTED)){
File FilePath = Environment.getExternalStorageDirectory();
File file = new File(FilePath,"data");
FileOutputStream os = null;
try {
os = new FileOutputStream(file);
os.write(content.getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (os!=null)
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private String readFile(){
String state = Environment.getExternalStorageState();
if (state.equals(Environment.MEDIA_MOUNTED)) {
File FilePath = Environment.getExternalStorageDirectory();
File file = new File(FilePath,"data");
FileInputStream is = null;
BufferedReader br = null;
try {
is = new FileInputStream(file);
br = new BufferedReader(new InputStreamReader(is));
String data = br.readLine();
return data;
} catch (Exception e) {
e.printStackTrace();
}finally {
if (is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(br!=null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return null;
}
}
布局文件跟上面一样。
运行效果:
文件目录:
当选择存储方式时,需要根据实际需求来确定使用内部存储还是外部存储。如果您的数据仅由应用程序使用并且需要保持私密性,建议使用内部存储。如果您需要共享文件或者存储大量的媒体文件,可以考虑使用外部存储。
二、使用SharePreferences存储
SharedPreferences 是一种轻量级的存储机制,用于在 Android 应用程序中保存和检索简单的键值对数据。它适用于存储应用程序的配置信息、用户偏好设置等,通常用于保存小量的数据。
1、SharedPreferences常用方法:
(1)、存储数据:
putString(String key, String value)
: 存储一个字符串类型的值。putInt(String key, int value)
: 存储一个整数类型的值。putLong(String key, long value)
: 存储一个长整数类型的值。putFloat(String key, float value)
: 存储一个浮点数类型的值。putBoolean(String key, boolean value)
: 存储一个布尔类型的值。
(2)、读取数据:
getString(String key, String defaultValue)
: 获取一个字符串类型的值,如果找不到对应的键,则返回默认值。getInt(String key, int defaultValue)
: 获取一个整数类型的值,如果找不到对应的键,则返回默认值。getLong(String key, long defaultValue)
: 获取一个长整数类型的值,如果找不到对应的键,则返回默认值。getFloat(String key, float defaultValue)
: 获取一个浮点数类型的值,如果找不到对应的键,则返回默认值。getBoolean(String key, boolean defaultValue)
: 获取一个布尔类型的值,如果找不到对应的键,则返回默认值。
(3)、删除数据:
remove(String key)
: 根据键删除对应的键值对。clear()
: 清除所有的键值对数据。
(4)、判断键是否存在:
contains(String key)
: 判断是否存在指定的键。
2、存储数据的步骤:
1、获取SharePreferences对象
2、获取编辑器(Editor是使用(key/value)键值对的形式存储数据保存在data/data/<packagename>/shared_prefs文件夹下XML文件中)
注意:value值的类型只能是float、int、long、String、boolean、Set<String>
3、使用PutXxx()方法存储数据
4、提交修改
存储数据的步骤代码如下:
private void write(String key,String value){
sp = getSharedPreferences("data",MODE_PRIVATE);
editor = sp.edit();
editor.putString(key,value);
editor.commit();
}
3、SharePreferences例子:
MainActivity:
package com.example.filesp;
import androidx.appcompat.app.AppCompatActivity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
Button write_btn,read_btn,clear_btn;
TextView read_tv,text;
EditText key_ed,value_ed,check_key;
SharedPreferences sp;
SharedPreferences.Editor editor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
write_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
write(key_ed.getText().toString(),value_ed.getText().toString());
key_ed.setText("");
value_ed.setText("");
}
});
read_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
read_tv.setText(read(check_key.getText().toString()));
}
});
clear_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
clear(check_key.getText().toString());
}
});
}
private void initView() {
read_btn = findViewById(R.id.read_btn);
read_tv = findViewById(R.id.value_tv);
write_btn = findViewById(R.id.write_btn);
value_ed = findViewById(R.id.value_ed);
key_ed = findViewById(R.id.key_ed);
text = findViewById(R.id.text);
check_key = findViewById(R.id.check_key);
clear_btn = findViewById(R.id.clear_btn);
}
private void write(String key,String value){
sp = getSharedPreferences("data",MODE_PRIVATE);
editor = sp.edit();
editor.putString(key,value);
editor.commit();
}
private String read(String key){
if(sp!=null){
String data = sp.getString(key,"");
return data;
}else
return "查询失败";
}
// 注意:程序要重新运行才能删除上次存储的数据
private void clear(String key){
if (editor!=null){
editor.remove(key); // 删除一条数据
// editor.clear(); 删除所有数据
text.setText(key+"删除成功");
}else {
text.setText(key+"删除失败");
}
}
}
anctivity_main:
<?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=".MainActivity">
<EditText
android:id="@+id/key_ed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入需要保存的数据的key:"
/>
<EditText
android:id="@+id/value_ed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入需要保存的数据的value:"
/>
<Button
android:id="@+id/write_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:text="保存数据"
android:layout_gravity="center"
/>
<EditText
android:id="@+id/check_key"
android:hint="请输入需要查询数据的key:"
android:layout_width="match_parent"
android:layout_height="100dp"
android:textSize="18sp"/>
<TextView
android:id="@+id/value_tv"
android:layout_width="match_parent"
android:layout_height="100dp"
android:textSize="18sp"
/>
<Button
android:id="@+id/read_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="读取数据"
android:textSize="18sp" />
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="100dp"
android:textSize="18sp"
/>
<Button
android:id="@+id/clear_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="18sp"
android:text="删除数据"/>
</LinearLayout>
运行效果: