一直对android系统各种的存储路径理的不是很清晰,只知道有手机内部存储和外部存储(一般为sd卡存储),今天把获取存储路径的API使用和区别详细看了一遍,在这里做个小结。
从android 1.0系统开始,往sd卡的写入操作需要在清单文件添加WRITE_EXTERNAL_STORAGE权限。
从android 4.1系统开始,读取sd的操作需要在清单文件添加WRITE_EXTERNAL_STORAGE权限。
从android 4.4系统开始,应用可以管理在它外部存储上的特定包名目录,且不需要添加读写权限。外部存储上有一个Android文件夹,在其data目录下一组文件夹,分别是各个应用的包名。context.getExternalCacheDir()和context.getExternalFilesDir(String type)两个方法分别可以获取对应包名下的cache和files文件目录,getExternalFilesDir方法中需传入一个文件夹类型,当type为Environment.DIRECTORY_DCIM,则会在files目录下创建一个DCIM文件夹,传入其他参数会生成对应的文件夹。
举个栗子,对包名为com.jaya.storagedemo的应用,getExternalCacheDir获取到的存储目录:/storage/emulated/0/Android/data/com.jaya.storagedemo/cache,getExternalFilesDir(Environment.DIRECTORY_DCIM)获取到的目录:/storage/emulated/0/Android/data/com.jaya.storagedemo/files/DCIM。
当我们在开发中想在本地缓存文件时,可以保存在sd卡上的Android/data/包名/,这样的好处一是可以充分利用sd卡的存储空间,只要不超过sd卡存储大小即可,另外当我们卸载应用时Android/data下包名对应的文件夹会被系统删除。当然如果是重要的私密文件还是保存在手机内部存储中更为安全。
获取存储路径的方法主要在Environment和Context两个类中,我们可以如下
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("wenqiao", "Environment.getDataDirectory():" + Environment.getDataDirectory().getAbsolutePath());
Log.i("wenqiao", "Environment.getExternalStorageDirectory():" + Environment.getExternalStorageDirectory().getAbsolutePath());
Log.i("wenqiao", "Environment.getRootDirectory():" + Environment.getRootDirectory().getAbsolutePath());
Log.i("wenqiao", "Environment.getDownloadCacheDirectory():" + Environment.getDownloadCacheDirectory().getAbsolutePath());
/**
* 这个方法接收一个参数,表明目录所放的文件的类型,传入的参数是Environment类中的DIRECTORY_XXX静态变量,比如DIRECTORY_DCIM等.
* 注意:传入的类型参数不能是null,返回的目录路径有可能不存在,所以必须在使用之前确认一下,比如使用File.mkdirs创建该路径。
*/
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_ALARMS);
if( !path.exists() ){
path.mkdirs();
}
/* /storage/emulated/0/Alarms */
Log.i("wenqiao", "Environment.getExternalStoragePublicDirectory():" + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_ALARMS));
/**
* contextWrapper
*/
Log.i("wenqiao", "getCacheDir():" + this.getCacheDir().getAbsolutePath());
Log.i("wenqiao", "getFilesDir():" + this.getFilesDir().getAbsolutePath());
Log.i("wenqiao", "getExternalCacheDir():" + this.getExternalCacheDir().getAbsolutePath());
Log.i("wenqiao", "getExternalFilesDir():" + this.getExternalFilesDir(Environment.DIRECTORY_DCIM).getAbsolutePath());
Log.i("wenqiao", "getPackageResourcePath():" + this.getPackageResourcePath());
Log.i("wenqiao", "getDir():" + this.getDir("myfile", Context.MODE_PRIVATE));
}
}
在华为荣耀6上测试结果:
02-15 15:28:24.154: I/wenqiao(12821): Environment.getDataDirectory():/data
02-15 15:28:24.157: I/wenqiao(12821): Environment.getExternalStorageDirectory():/storage/emulated/0
02-15 15:28:24.157: I/wenqiao(12821): Environment.getRootDirectory():/system
02-15 15:28:24.157: I/wenqiao(12821): Environment.getDownloadCacheDirectory():/cache
02-15 15:28:24.168: I/wenqiao(12821): Environment.getExternalStoragePublicDirectory():/storage/emulated/0/Alarms
02-15 15:28:24.168: I/wenqiao(12821): getCacheDir():/data/user/0/com.jaya.storagedemo/cache
02-15 15:28:24.170: I/wenqiao(12821): getFilesDir():/data/user/0/com.jaya.storagedemo/files
02-15 15:28:24.172: I/wenqiao(12821): getExternalCacheDir():/storage/emulated/0/Android/data/com.jaya.storagedemo/cache
02-15 15:28:24.175: I/wenqiao(12821): getExternalFilesDir():/storage/emulated/0/Android/data/com.jaya.storagedemo/files/DCIM
02-15 15:28:24.175: I/wenqiao(12821): getPackageResourcePath():/data/app/com.jaya.storagedemo-2/base.apk
02-15 15:28:24.175: I/wenqiao(12821): getDir():/data/user/0/com.jaya.storagedemo/app_myfile
其中,/data/user/0目录其实就是/data/data目录,可以看出,getCacheDir和getFilesDir获取的是手机内部存储中应用包名下的cache和files文件夹,getDir则获取应用包名的文件夹,其中传入的是要获取的文件夹名。
此外,context还可以通过openFileInput(name)和openFileOutput(name, mode)获取FileInputStream和FileOutputStream,分别对应的是/data/user/0/包名/files/下的文件输入流和输出流。name是文件名,mode指定打开文件的模式,有以下几种:
Context.MODE_PRIVATE 默认模式,表示文件只能被自身应用访问,如果向文件中写入数据,会覆盖之前数据
Context.MODE_MODE_APPEND 文件写入时,文件不存在则创建文件,存在则在已有的内容上追加
Context.MODE_MODE_WORLD_READABLE 表示文件可以被其他应用读取
Context.MODE_WORLD_WRITEABLE 表示文件可以被其他文件写入
当调用openFileOutput时,如果文件不存在,系统会创建文件。