这边文章是为了记录Android文件保存的详细内容及API,同时方便以后查阅。在了解Android文件保存之前,首先我们得知道什么是外部存储和内部存储。
选择内部或外部存储
所有 Android 设备都有两个文件存储区域:“内部”和“外部”存储。这些名称在 Android 早期产生,当时大多数设备都提供内置的非易失性内存(内部存储),以及移动存储介质,比如微型 SD 卡(外部存储)。一些设备将永久性存储空间划分为“内部”和“外部”分区,即便没有移动存储介质,也始终有两个存储空间,并且无论外部存储设备是否可移动,API 的行为均一致。以下列表汇总了关于各个存储空间的实际信息。
内部存储:
当您希望确保用户或其他应用均无法访问您的文件时,内部存储是最佳选择。
外部存储:
getExternalFilesDir()
将您的应用的文件保存在目录中时,系统才会从此处移除您的应用的文件。对于无需访问限制以及您希望与其他应用共享或允许用户使用计算机访问的文件,外部存储是最佳位置。
要向外部存储写入信息,您必须在您的清单文件中请求 WRITE_EXTERNAL_STORAGE
权限。
...>
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
...
注意:目前,所有应用都可以读取外部存储,而无需特别的权限。 但这在将来版本中会进行更改。如果您的应用需要读取外部存储(但不向其写入信息),那么您将需要声明 READ_EXTERNAL_STORAGE
权限。要确保您的应用继续正常工作,您应在更改生效前声明此权限。
...>
android:name="android.permission.READ_EXTERNAL_STORAGE" />
...
但是,如果您的应用使用 WRITE_EXTERNAL_STORAGE
权限,那么它也隐含读取外部存储的权限。
您无需任何权限,即可在内部存储中保存文件。 您的应用始终具有在其内部存储目录中进行读写的权限。
在内部存储中保存文件时,您可以通过调用以下两种方法之一获取作为 File
的相应目录:
getFilesDir()
File
。
getCacheDir()
File
。 务必删除所有不再需要的文件并对在指定时间您使用的内存量实现合理大小限制,比如,1MB。 如果在系统即将耗尽存储,它会在不进行警告的情况下删除您的缓存文件。
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
直接看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