Android 中内部存储和外部存储的理解与应用

博主前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住也分享一下给大家,
👉点击跳转到网站

一、Android存储分为:

内部存储(Internal Storage)和外部存储(External Storage)

特点

  1. 内部存储:随应用卸载被删除
  2. 外部存储:
    1.公有目录:存放一些下载的视频文件等,比如还有movies,fictures,music等公有的一些文件目录
    2.私有目录:随应用卸载被删除

下面来具体介绍一下内部存储和外部存储的具体路径:

1、内部存储:不需要任何权限

  1. /data/data/< applicationId,就是包名 >/shared_prefs
  2. /data/data/< applicationId >/databases
  3. /data/data/< applicationId >/files 通过context.getFilesDir() 获取该目录
  4. /data/data/< applicationId >/cache 通过context.getCacheDir() 获取该目录

Android SDK提供了几个常见的内部存储文件的权限

  1. Context.MODE_PRIVATE :私有方式存储,其他应用无法访问,覆盖旧的同名文件
  2. Context.MODE_APPEND:私有方式存储,若有旧的同名文件,则在该文件上追加数据

2、外部存储:

  1. 公有目录: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();
  1. 私有目录:
    /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_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".InternalActivity">

    <EditText
        android:id="@+id/edit_username"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        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_width="match_parent"
        android:layout_height="wrap_content"
        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_width="match_parent"
        android:layout_height="wrap_content"
        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_width="match_parent"
        android:layout_height="wrap_content"
        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_width="match_parent"
        android:layout_height="wrap_content"
        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_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ExternalActivity">

    <EditText
        android:id="@+id/edit_username"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        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_width="match_parent"
        android:layout_height="wrap_content"
        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_width="match_parent"
        android:layout_height="wrap_content"
        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_width="match_parent"
        android:layout_height="wrap_content"
        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_width="match_parent"
        android:layout_height="wrap_content"
        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);
    }
}
  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Android内部路径和外部存储路径的区别在于其访问权限存储位置。 Android内部路径是指应用程序在设备的内部存储空间创建的路径。这个路径只能被应用程序本身访问,其他应用程序、用户或系统都无法直接访问。内部路径通常用于存储应用程序的私密数据,如缓存文件、数据库文件等。由于内部路径只能被应用程序访问,所以应用程序对其具有读写权限,并且可以在应用程序卸载时将内部路径下的数据一并删除。 而外部存储路径则是指设备上的可移动存储介质,如SD卡。这个路径是被所有应用程序以及使用设备的用户和系统共享的,因此外部存储路径的数据可以被多个应用程序共享和访问。外部存储路径通常用于存储大量的公共数据,如音频、视频、图片等。由于外部存储路径是共享的,所以应用程序对其只具有读写权限,并且应用程序卸载时不会删除外部存储路径下的数据。 需要注意的是,由于外部存储路径是被所有应用程序共享的,所以访问外部存储路径需要申请相关的权限,并且需要注意防止数据被其他应用程序非法访问或篡改。在使用外部存储路径时,还需要进行容量检测,以确保设备上有足够的可用存储空间。 综上所述,Android内部路径和外部存储路径在访问权限存储位置和数据共享等方面存在区别。根据应用程序的需求和数据的性质,开发者可以选择合适的路径来存储和管理数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路宇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值