Android 中内部存储和外部存储的理解与应用
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 中内部存储和外部存储的理解与应用相关的知识,希望对你有一定的参考价值。
一、Android存储分为:
内部存储(Internal Storage)和外部存储(External Storage)
特点
:
- 内部存储:随应用卸载被删除
- 外部存储:
1.公有目录:存放一些下载的视频文件等,比如还有movies,fictures,music等公有的一些文件目录
2.私有目录:随应用卸载被删除
下面来具体介绍一下内部存储和外部存储的具体路径:
1、内部存储:不需要任何权限
- /data/data/< applicationId,就是包名 >/shared_prefs
- /data/data/< applicationId >/databases
- /data/data/< applicationId >/files 通过context.getFilesDir() 获取该目录
- /data/data/< applicationId >/cache 通过context.getCacheDir() 获取该目录
android SDK提供了几个常见的内部存储文件的权限
- Context.MODE_PRIVATE :私有方式存储,其他应用无法访问,覆盖旧的同名文件
- Context.MODE_APPEND:私有方式存储,若有旧的同名文件,则在该文件上追加数据
2、外部存储:
- 公有目录:Environment.getExternalStoragePublicDirectory(int type),这里的type类型不能为空,可以是DIRECTORY_MUSIC,DIRECTORY_MOVIES等 通过这个方法获取公有目录下相对应的文件
Environment.getExternalStorageDirectory()也可以获取。
注:Environment是操作SD卡的工具类
//publicDirectory路径为:/storage/emulated/0/Movies
String publicDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES).getAbsolutePath();
//sdPath路径为: /storage/emulated/0
String sdPath = Environment.getExternalStorageDirectory().getAbsolutePath();
- 私有目录:
/mnt/sdcard/Android/data/data/< applicationId >/cache 通过getExternalCacheDir().getAbsolutePath()得到的路径为:
/storage/emulated/0/Android/data/包名/cache等价于上面的路径。
/mnt/sdcard/Android/data/data/< applicationId >/files 通过getExternalFilesDir().getAbsolutePath()方法可以获取到路径为:
/storage/emulated/0/Android/data/包名/files等价于上面的路径。
注意:
外部存储的私有目录文件会随着应用的卸载而被删除,公有目录则不会被删除。
再看一下具体区别:
下面演示内部存储数据的一个实例
一、activity_internal.xml布局文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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_
android:layout_
tools:context=".InternalActivity">
<EditText
android:id="@+id/edit_username"
android:layout_
android:layout_
android:hint="请输入用户名"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/edit_password"
android:layout_
android:layout_
android:hint="请输入密码"
android:inputType="textPassword"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/edit_username" />
<Button
android:id="@+id/btn_save_userMessage"
android:layout_
android:layout_
android:text="保存用户信息"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/edit_password" />
<Button
android:id="@+id/btn_read"
android:layout_
android:layout_
android:text="读取用户信息"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_save_userMessage" />
<TextView
android:id="@+id/tv_message"
android:layout_
android:layout_
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_read" />
</androidx.constraintlayout.widget.ConstraintLayout>
二、InternalActivity类,实现具体的存储和读取操作
public class InternalActivity extends AppCompatActivity implements View.OnClickListener
private EditText edit_username;
private EditText edit_password;
private Button btn_save_userMessage;
private Button btn_read;
private TextView tv_message;
//文件名
private String fileName = "test";
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_internal);
edit_username = findViewById(R.id.edit_username);
edit_password = findViewById(R.id.edit_password);
btn_save_userMessage = findViewById(R.id.btn_save_userMessage);
btn_read = findViewById(R.id.btn_read);
tv_message = findViewById(R.id.tv_message);
btn_save_userMessage.setOnClickListener(this);
btn_read.setOnClickListener(this);
@Override
public void onClick(View v)
switch (v.getId())
case R.id.btn_save_userMessage:
String username = edit_username.getText().toString();
String password = edit_password.getText().toString();
if (TextUtils.isEmpty(username))
Toast.makeText(this, "用户名不能为空!", Toast.LENGTH_SHORT).show();
return;
if (TextUtils.isEmpty(password))
Toast.makeText(this, "密码不能为空!", Toast.LENGTH_SHORT).show();
return;
FileOutputStream fos = null;
try
//第一个参数:文件名
//第二个参数:表示文件输出的类型 这里选择Context.MODE_PRIVATE每次生成相同的文件名,则覆盖原有的文件
fos = openFileOutput(fileName, Context.MODE_PRIVATE);
String nameAndPassword = username + "." + password;
byte[] bytes = nameAndPassword.getBytes();
fos.write(bytes);
catch (Exception e)
e.printStackTrace();
finally
if (fos != null)
try
fos.close();
catch (IOException e)
e.printStackTrace();
Toast.makeText(this, "保存成功!", Toast.LENGTH_SHORT).show();
break;
case R.id.btn_read:
FileInputStream fis = null;
try
fis = openFileInput(fileName);
//fis.available() 判断文件有多少个字节
byte[] bytes = new byte[fis.available()];
while (fis.read(bytes) != -1)
String message = new String(bytes);
String[] split = message.split("\\\\.");
tv_message.setText("用户名:" + split[0] + "\\n" + "密码:" + split[1]);
catch (Exception e)
e.printStackTrace();
break;
default:
break;
效果演示如下:
下面演示外部存储数据的一个实例
一、布局页面activity_external.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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_
android:layout_
tools:context=".ExternalActivity">
<EditText
android:id="@+id/edit_username"
android:layout_
android:layout_
android:hint="请输入用户名"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/edit_password"
android:layout_
android:layout_
android:hint="请输入密码"
android:inputType="textPassword"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/edit_username" />
<Button
android:id="@+id/btn_save_userMessage"
android:layout_
android:layout_
android:text="保存用户信息到外部存储"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/edit_password" />
<Button
android:id="@+id/btn_read"
android:layout_
android:layout_
android:text="从外部存储读取用户信息"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_save_userMessage" />
<TextView
android:id="@+id/tv_message"
android:layout_
android:layout_
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_read" />
</androidx.constraintlayout.widget.ConstraintLayout>
二、ExternalActivity类实现保存和读取数据的功能。
注意
:在使用外部存储之前,需要调用Environment类的getExternalStorageState()方法来检查存储介质状态,是否可用。还是仅可以读,不能写等。
public class ExternalActivity extends AppCompatActivity implements View.OnClickListener
private EditText edit_username;
private EditText edit_password;
private Button btn_save_userMessage;
private Button btn_read;
private TextView tv_message;
//文件名
private String fileName = "test";
//外部状态可用
boolean mExternalStorageAvailable = false;
//外部状态可写
boolean mExternalStorageWrite = false;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_external);
edit_username = findViewById(R.id.edit_username);
edit_password = findViewById(R.id.edit_password);
btn_save_userMessage = findViewById(R.id.btn_save_userMessage);
btn_read = findViewById(R.id.btn_read);
tv_message = findViewById(R.id.tv_message);
btn_save_userMessage.setOnClickListener(this);
btn_read.setOnClickListener(this);
@Override
public void onClick(View v)
switch (v.getId())
case R.id.btn_save_userMessage:
String username = edit_username.getText().toString();
String password = edit_password.getText().toString();
if (TextUtils.isEmpty(username))
Toast.makeText(this, "用户名不能为空!", Toast.LENGTH_SHORT).show();
return;
if (TextUtils.isEmpty(password))
Toast.makeText(this, "密码不能为空!", Toast.LENGTH_SHORT).show();
return;
//首先判断外部存储设备的状态
checkExternalStorage();
OutputStream outputStream = null;
try
if (mExternalStorageWrite)
outputStream = new FileOutputStream(new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), fileName));
String nameAndPassword = username + "." + password;
byte[] bytes = nameAndPassword.getBytes();
outputStream.write(bytes);
catch (Exception e)
e.printStackTrace();
finally
if (outputStream != null)
try
outputStream.close();
catch (IOException e)
e.printStackTrace();
Toast.makeText(this, "保存成功!", Toast.LENGTH_SHORT).show();
break;
case R.id.btn_read:
checkExternalStorage();
FileInputStream fis = null;
try
//第一个参数:文件目录 第二个参数:文件名
//getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)对应的路径为:
// /storage/emulated/0/Android/data/com.example.customviewproject/files/Download
File file = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), fileName);
if (mExternalStorageAvailable)
fis = new FileInputStream(file);
//判断当前文件的字节个数
byte[] bytes = new byte[fis.available()];
while (fis.read(bytes) != -1)
String message = new String(bytes);
String[] split = message.split("\\\\.");
tv_message.setText("用户名:" + split[0] + "\\n" + "密码:" + split[1]);
catch (Exception e)
e.printStackTrace();
finally
if (fis != null)
try
fis.close();
catch (IOException e)
e.printStackTrace();
break;
default:
break;
private void checkExternalStorage()
//获取外部存储器的状态
String state = Environment.getExternalStorageState();
//主要有两种状态
//外部状态可用
if (Environment.MEDIA_MOUNTED.equals(state))
//外部存储器可用 表示既可以写 也可以读
mExternalStorageAvailable = true;
mExternalStorageWrite = true;
else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state))
//外部存储器可用 表示仅可以读 不可写
mExternalStorageAvailable = true;
mExternalStorageWrite = false;
else //表示为不可用的状态
mExternalStorageAvailable = false;
mExternalStorageWrite = false;
效果演示:
操作assets目录下的图片文件,进行内部存储与读取操作,代码如下
public class InnerFileActivity extends AppCompatActivity
private ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_inner_file);
imageView = findViewById(R.id.imageView);
public void save(View view)
//操作assets目录下的文件
AssetManager manager = getAssets();
try
//得到assets目录下图片的输入流 \\src\\main\\assets\\logo.png
InputStream is = manager.open("logo.png");
//输出流指向的路径为:/data/data/com.example.customviewproject/files/logo.png
FileOutputStream fileOutputStream = openFileOutput("logo.png", Context.MODE_PRIVATE);
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1)
fileOutputStream.write(buffer, 0, len);
fileOutputStream.close();
is.close();
Toast.makeText(this, "保存成功!", Toast.LENGTH_SHORT).show();
catch (IOException e)
e.printStackTrace();
public void read(View view)
/**
* 图片保存的路径为: /data/data/com.example.customviewproject/files/logo.png
*/
//1.得到图片文件路径
//filesPath为: /data/user/0/com.example.customviewproject/files
String filesPath = getFilesDir().getAbsolutePath();
String imagePath = filesPath + "/logo.png";
//根据图片路径得到bitmap对象
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
imageView.setImageBitmap(bitmap);
以上是关于Android 中内部存储和外部存储的理解与应用的主要内容,如果未能解决你的问题,请参考以下文章