Android 文件保存getFilesDir()丶getCacheDir()、getExternalFilesDir() 等操作方法探索

这边文章是为了记录Android文件保存的详细内容及API,同时方便以后查阅。在了解Android文件保存之前,首先我们得知道什么是外部存储和内部存储


选择内部或外部存储


所有 Android 设备都有两个文件存储区域:“内部”和“外部”存储。这些名称在 Android 早期产生,当时大多数设备都提供内置的非易失性内存(内部存储),以及移动存储介质,比如微型 SD 卡(外部存储)。一些设备将永久性存储空间划分为“内部”和“外部”分区,即便没有移动存储介质,也始终有两个存储空间,并且无论外部存储设备是否可移动,API 的行为均一致。以下列表汇总了关于各个存储空间的实际信息。

内部存储:

  • 它始终可用。
  • 只有您的应用可以访问此处保存的文件。
  • 当用户卸载您的应用时,系统会从内部存储中移除您的应用的所有文件。

当您希望确保用户或其他应用均无法访问您的文件时,内部存储是最佳选择。

外部存储:

  • 它并非始终可用,因为用户可采用 USB 存储设备的形式装载外部存储,并在某些情况下会从设备中将其移除。
  • 它是全局可读的,因此此处保存的文件可能不受您控制地被读取。
  • 当用户卸载您的应用时,只有在您通过 getExternalFilesDir() 将您的应用的文件保存在目录中时,系统才会从此处移除您的应用的文件。

对于无需访问限制以及您希望与其他应用共享或允许用户使用计算机访问的文件,外部存储是最佳位置。













获取外部存储的权限


要向外部存储写入信息,您必须在您的清单文件中请求 WRITE_EXTERNAL_STORAGE 权限。

<manifest ...>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    ...
</manifest>

注意:目前,所有应用都可以读取外部存储,而无需特别的权限。 但这在将来版本中会进行更改。如果您的应用需要读取外部存储(但不向其写入信息),那么您将需要声明 READ_EXTERNAL_STORAGE 权限。要确保您的应用继续正常工作,您应在更改生效前声明此权限。

<manifest ...>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    ...
</manifest>

但是,如果您的应用使用 WRITE_EXTERNAL_STORAGE 权限,那么它也隐含读取外部存储的权限。

您无需任何权限,即可在内部存储中保存文件。 您的应用始终具有在其内部存储目录中进行读写的权限。


一、内部存储路径探索(官方介绍)


在内部存储中保存文件时,您可以通过调用以下两种方法之一获取作为 File 的相应目录:

getFilesDir()
返回表示您的应用的内部目录的  File 。
getCacheDir()
返回表示您的应用临时缓存文件的内部目录的  File。 务必删除所有不再需要的文件并对在指定时间您使用的内存量实现合理大小限制,比如,1MB。 如果在系统即将耗尽存储,它会在不进行警告的情况下删除您的缓存文件。

下面是我的demo打印出的效果展示(内部存储)


getFilesDir():/data/user/0/com.liuzhongjun.developertest/files
getCacheDir():/data/user/0/com.liuzhongjun.developertest/cache
getDataDir():/data/user/0/com.liuzhongjun.developertest  (API 24 新增)
getDataDirectory():/data
getDownloadCacheDirectory():/cache



解释一下:
/data/user/0/com.liuzhongjun.developertest 这一个路径的 /data/user/0/便是我们内部存储的根路径,而之后的 com.liuzhongjun.developertest 就是我们的包名。
getFilesDir()和getCacheDir()默认在 /date/user/0/(packgename) 目录下的, 这一目录在android系统设计之初就是默认隐藏的,手机root后才能显示。




二、外部存储路径探索

直接看Demo打印效果

getExternalStorageState():mounted
getExternalStorageDirectory():/storage/emulated/0
getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES):/storage/emulated/0/Movies
getExternalCacheDir():/storage/emulated/0/Android/data/com.liuzhongjun.developertest/cache
getExternalFilesDir(Environment.DIRECTORY_MOVIES):/storage/emulated/0/Android/data/com.liuzhongjun.developertest/files/Movies



首先大家应该知道getExternalStorageState()是判断有无外部存储,返回mounted表示可以使用。进而可以调用以下的方法。


getExternalStorageDirectory()为外部存储根目录 文件/storage/emulated/0 就是这个路径了(我们进入的sd卡也就是进入的这个目录)。

getExternalStoragePublicDirectory() 表示外部存储设备上相应目录的 文件,必须传入一个参数,比如这里我传入的Environment.DIRECTORY_MOVIES返回的便是Movies的公共文件,如果传入的为空字符串(注意不能为null,否则会报错),则返回路径则与getExternalStorageDirectory()相同。


getExternalCacheDir()表示应用的外部缓存目录 文件

而getExternalFilesDir()表示应用的专用文件目录 文件这里也必须传入一个参数,参数类型与getExternalStoragePublicDirectory()中传递的参数相同,返回路径当然也是类似了;不过我们在这里就能传空值了,此时就是返回外部存储上应用的专用目录的根目录

外部目录我们都能够在手机文件中查看到相应目录文件。




小节:

注意:除getExternalStorageState()外,其他的这几个方法返回值类型都是File;


getFilesDir()、getCacheDir、getExternalCacheDir()、getExternalFilesDir()
这几个方法下的目录因为都是与我们应用有关的目录,因此当我们的APP被卸载后其中的文件也会被清空。
所以这里如果想在APP被卸载后保留相关的文件,建议使用getExternalStorageDirectory()或者getExternalStoragePublicDirectory()自行处理文件读写。




下面是源代码,大家可以自行copy测试

public class MainActivity extends AppCompatActivity {
    
    public static final String TAG = "MainActivity";

    private TextView mPath;
    private TextView mDesc;
    private RadioGroup mRadioGroup;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mPath = (TextView) findViewById(R.id.path);
        mDesc = (TextView) findViewById(R.id.desc);
        mRadioGroup = (RadioGroup) findViewById(R.id.radio_group);

        //
        mRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {

                File path;
                String desc = "";
                int api = 1;            // Api 最低需求.
                switch (checkedId) {

                    // Internal Storage
                    case R.id.getDataDirectory:
                        path = getDataDirectory();
                        desc = "数据目录";
                        break;

                    case R.id.getFilesDir:
                        path = getFilesDir();
                        desc = "程序数据目录";
                        break;

                    case R.id.getCacheDir:
                        path = getCacheDir();
                        desc = "程序缓存目录";
                        break;

                    case R.id.getDownloadCacheDirectory:
                        path = Environment.getDownloadCacheDirectory();
                        desc = "下载缓存内容目录";
                        break;

                    // External Storage
                    // Don't be confused by the word "external" here.
                    // These directories can better be thought as media/shared storage.
                    case R.id.getExternalStorageDirectory:
                        path = Environment.getExternalStorageDirectory();
                        desc = "共享目录. 但是这个目录很可能当前不能访问,比如这个目录被用户的PC挂载,或者从设备中移除,或者其他问题发生,你可以通过getExternalStorageState()来获取当前状态。";
                        break;

                    case R.id.Context_getExternalFilesDir:
                        path = getExternalFilesDir(Environment.DIRECTORY_MUSIC);
                        desc = "任何应用私有的文件的应该被放置在 getExternalFilesDir 返回的目录下,在应用被卸载的时候,系统会清理的就是这个目录。";
                        api = 8;
                        break;

                    case R.id.getExternalStoragePublicDirectory:
                        path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
                        desc = "共享目录下的分类目录";
                        api = 8;
                        break;

                    case R.id.getExternalCacheDir:
                        path = getExternalCacheDir();
                        api = 8;
                        break;

                    default:
                        path = null;
                        desc = null;
                        api = 0;
                        break;
                }

                if (api != 1) {
                    desc = String.format("%s (API: %d)", desc, api);
                }

                mPath.setText(path.getAbsolutePath());
                mDesc.setText(desc);
            }
        });

        //
        mRadioGroup.check(R.id.getDataDirectory);
    }


    public static final String INTERNAL = "InternalStorget";
    public static final String EXTERNAL = "ExternalStorget";

    /**
     * 打印文件目录效果
     *
     * @param view
     */
    public void showLog(View view) {

        Log.d(TAG, "--------------内部存储---------------");
        Log.i(INTERNAL, "getCacheDir():" + getCacheDir());
        Log.i(INTERNAL, "getFilesDir():" + getFilesDir());
        Log.i(INTERNAL, "getDataDirectory():" + Environment.getDataDirectory());
        Log.i(INTERNAL, "getDownloadCacheDirectory():" + Environment.getDownloadCacheDirectory());

        Log.e(TAG, "----------------------------这里是分割线----------------------------");

        Log.d(TAG, "--------------外部存储---------------");
        Log.i(EXTERNAL, "getExternalStorageState():" + Environment.getExternalStorageState());
        Log.i(EXTERNAL, "getExternalStorageDirectory():" + Environment.getExternalStorageDirectory());
        Log.i(EXTERNAL, "getExternalStoragePublicDirectory(\"\"):" + Environment.getExternalStoragePublicDirectory(""));
        Log.i(EXTERNAL, "getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES):" + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES));
        Log.i(EXTERNAL, "getExternalCacheDir:" + getExternalCacheDir());
        Log.i(EXTERNAL, "getExternalFilesDir(null):" + getExternalFilesDir(null));
        Log.i(EXTERNAL, "getExternalFilesDir(Environment.DIRECTORY_MOVIES):" + getExternalFilesDir(Environment.DIRECTORY_MOVIES));

    }


}



布局Layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.liuzhongjun.developertest.MainActivity">


    <TextView
        android:id="@+id/path"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="4324" />

    <TextView
        android:id="@+id/desc"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/path"
        android:text="1121" />

    <RadioGroup
        android:id="@+id/radio_group"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true">

        <!--External Storage-->
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="Internal Storage"
            android:textSize="18sp" />

        <RadioButton
            android:id="@+id/getCacheDir"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="getCacheDir()" />

        <RadioButton
            android:id="@+id/getFilesDir"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="getFilesDir()" />

        <RadioButton
            android:id="@+id/getDataDirectory"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="getDataDirectory()" />

        <RadioButton
            android:id="@+id/getDownloadCacheDirectory"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="getDownloadCacheDirectory()" />


        <!--External Storage-->
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="External Storage"
            android:textSize="18sp" />

        <RadioButton
            android:id="@+id/getExternalStorageDirectory"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="getExternalStorageDirectory()" />


        <RadioButton
            android:id="@+id/getExternalStoragePublicDirectory"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="getExternalStoragePublicDirectory(String)" />

        <RadioButton
            android:id="@+id/getExternalCacheDir"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="getExternalCacheDir()" />

        <RadioButton
            android:id="@+id/Context_getExternalFilesDir"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="getExternalFilesDir(String)" />


    </RadioGroup>

    <Button
        android:id="@+id/btn_showFile"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_below="@+id/desc"
        android:layout_marginTop="44dp"
        android:onClick="showLog"
        android:text="Log打印所有效果" />

</RelativeLayout>











  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Android Studio 中,您可以使用以下方法将数据保存文件中: 1. 使用 SharedPreferences:SharedPreferences 是 Android 中用于保存键值对数据的一种轻量级的方式。您可以使用 SharedPreferences 将数据保存到应用程序的默认 SharedPreferences 文件中。要使用 SharedPreferences,请使用以下代码: ``` // 获取 SharedPreferences 对象 SharedPreferences preferences = getSharedPreferences("MyPrefsFile", MODE_PRIVATE); // 获取 SharedPreferences.Editor 对象 SharedPreferences.Editor editor = preferences.edit(); // 将数据保存到 SharedPreferences 文件中 editor.putString("key", "value"); editor.commit(); ``` 2. 使用内部存储:您可以使用内部存储保存应用程序的私有数据。要使用内部存储,请使用以下代码: ``` // 获取应用程序的内部存储目录 File file = new File(getFilesDir(), "data.txt"); // 使用 OutputStream 将数据写入文件中 try { OutputStream outputStream = new FileOutputStream(file); outputStream.write("Hello, world!".getBytes()); outputStream.close(); } catch (IOException e) { e.printStackTrace(); } ``` 3. 使用外部存储:您可以使用外部存储保存应用程序的公共数据。要使用外部存储,请使用以下代码: ``` // 获取外部存储目录 File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "data.txt"); // 使用 OutputStream 将数据写入文件中 try { OutputStream outputStream = new FileOutputStream(file); outputStream.write("Hello, world!".getBytes()); outputStream.close(); } catch (IOException e) { e.printStackTrace(); } ``` 请注意,使用外部存储需要声明特定的权限,并且用户可能会拒绝授予该权限。因此,请在使用外部存储时谨慎处理数据。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值