1.Android存储
Android存储分为内部存储和外部存储(外部存储并不是指SD存储卡或外部硬盘)。
①内部存储
用于Android系统本身和应用程序的存储区域,比如手机的/system/、/data/等目录。 如果没有这一块存储区域是无法运行Android系统和应用程序的。
其中data/data/包名/XXX是Android系统提供给app存储数据的内部存储空间,由app创建的SharedPreferences、Sqlite数据库、缓存文件等都保存在该文件夹中。该目录只能由该app自身访问,其他应用程序和用户无法访问存储在此空间中的文件,并且该目录会随着应用的卸载而被移除。
获取手机内部存储绝对路径/data的方法:
Environment.getDataDirectory().getAbsolutePath();
注意:如果手机获取到了root权限,就可以访问内部存储空间中的文件数据。
②外部存储
手机的内部存储空间通常不会很大,一旦手机的内部存储容量用完,可能会出现手机无法使用的情形。因此需要将一些比较大的媒体文件放到机身外部存储中。以前的手机中具备一个SD存储卡槽,插入SD存储卡,系统会将SD储存卡的存储空间挂载成外部存储空间。但是现在的手机已经不支持SD存储卡扩展功能了,取而代之的是手机自带了一个机身内置存储空间,这个机身存储和SD存储卡的功能是完全一样的,Android系统会将内置存储空间的一部分区域划分为内部存储,另一部分划分为外部存储,然后通过Linux文件挂载的方式将这些存储空间进行挂载。
获取手机外部存储的路径/storage/emulated/0的方法:
Environment.getExternalStorageDirectory().getAbsolutePath();
③现在很多手机自带的内置存储空间很大, 因此Android4.4系统及以上的手机将机身内置存储分为了内部存储internal和外部存储external两个不同的储存区域,用来存储不同的数据。
如果Android4.4系统及以上的手机还支持单独外接SD卡,那么外接的SD卡一定是外部存储,此时手机上是有两个外部存储空间的。为了区分这两个外部存储,google提供了getExternalFilesDirs方法,这个API可以获取多个外部存储空间,它返回一个File数组,File数组中就包含了手机自身所带的外部存储和外接SD卡所定义的外部存储了。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
File[] files = getExternalFilesDirs( Environment.MEDIA_MOUNTED);
for(File file:files){
Log.e("Environment", file.getAbsolutePath())
}
}
注意:Android手机支持外接多个外部存储介质空间,如果用户在设备上移除了介质,则外部存储可能变为不可用状态。 所以在使用外部存储执行任何工作之前, 最好调用getExternalStorageState()来检查介质是否可用。
//判断外部存储是否可用
if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
...
}
可见,内部存储和外部存储可以是在同一块存储介质上面的,只是概念上做了区分,即内部存储和外部存储是一块存储介质上的不同区域。
2.Android应用存储目录
①内部存储空间中的应用私有目录
对于每一个安装的App,系统都会在内部存储空间的data/data目录下以应用包名为名字自动创建与之对应的文件夹。这个文件夹包含SharedPreferences和SQLiteDatabase持久化应用相关数据等。该文件夹是应用的私有文件夹,其他应用和用户不能访问文件夹里面的内容的(Root用户除外)。每个应用访问自己的内部存储是不需要权限的。当用户卸载该应用时,这些文件也会被移除。
1)获取当前app包名文件夹下的files文件夹路径:
context.getFilesDir().getAbsolutePath();
返回结果:data/data/packagename/files
2)获取当前app包名文件夹下cache文件夹路径:
context.getCacheDir().getAbsolutePath();
返回结果:data/data/packagename/cache
3)在内部存储空间内创建或打开现有的目录:
context.getDir("setting", MODE_PRIVATE).getAbsolutePath();
返回结果:data/data/packagename/setting
4)获取内部存储files路径下的所有文件名:
context.fileList();
5)删除内部存储files路径下的文件:
//返回true则表示删除成功
context.deleteFile(filename);
6)要在files或cache目录中创建新文件,可以使用File()构造函数,传递给File上述方法提供的指定内部存储目录的方法:
//保存内容到私有的files目录
public void save(String filename, String content) throws IOException{
File file= new File(context.getFilesDir(), filename);
FileOutputStream myfos= new FileOutputStream(file);
myfos.write(content.getBytes());
myfos.close();
}
或者读取文件:
//通过文件名来获取私有的files目录中的文件
public String get(String filename) throws IOException {
File file= new File(context.getFilesDir(), filename);
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] data = new byte[1024];
int len = -1;
while ((len = fis.read(data)) != -1) {
baos.write(data, 0, len);
}
return new String(baos.toByteArray());
}
Android系统可以调用Context类中提供的openFileOutput()方法获取FileOutputStream来对文件进行操作。openFileOutput()方法接受两个参数:第一个参数是文件名,在文本创建的时候使用的就是这个名称,注意这里指定的文件名不可以包含路径(因为默认存储到/data/data//files/目录下)。第二个参数是文件的操作模式,主要有两种:MODE_PRIVATE:默认的操作模式,表示当指定同样文件名的时候,当该文件名有内容时,再次调用会覆盖原内容;MODE_APPEND:表示该文件如果已存在就往文件里面追加内容。
调用openFileOutput()获取FileOutputStream对象后就可以使用Java流的方式将数据写入到文件中了。
写入文件:
//保存内容到私有的files目录
public void save(String filename, String content) throws IOException{
FileoutputStream myfos=context.openFileoutput(filename,Contex