这边文章是为了记录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));

    }


}




<?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>