内部存储和外部存储
在Android4.4以前,内部存储(Internal Storage)就是指手机机身存储,而外部存储(External Storage)则指外置SD卡。
而在Android4.4及以后,在没有外置SD卡的情况下机身存储分为了内部存储(Internal Storage)和外部存储(External Storage);如果加上外置SD卡则外置SD卡和机身存储的外部存储都算作外部存储(External Storage)
//在Android4.4及以后提供了getExternalFilesDirs方法来获取所有的外置存储
File[] files = getExternalFilesDirs("");
Android系统中的文件夹
data目录
/data
目录就是所谓的内部存储(ROM),但是当手机没有root的时候不能打开此文件夹。
- data/app/
存放所有用户安装的apk文件,不包括系统默认应用文件
- data/data/包名/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jv9LwiLm-1661177297780)(https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/29/171257f84ba6265b~tplv-t2oaga2asx-image.image)]
每个应用的数据都存放在以包名为命名的文件夹下,如图:
- cache:缓存目录
- databases:数据库目录
- files:文件存储目录
- shared_prefs:SharedPreferences文件存储目录
- /data/misc/
这里存放着大部分的WIFI、VPN信息。
- /data/user/0/
/data/data
目录实际上软连接到/data/user/0
目录,相当于/data/data
目录是一个指针指向
/data/user/0
目录.
在Android4.2之后,Android推出了一个“多用户”的功能特征,意味着一台设备可能被多个人同时应用,因此需要将每个人的数据、应用、个性配置分开。为了区别数据就用数字来区别多用户,这里的0就是指第一个用户
软连接可用看Linux软连接和硬链接
system
Android系统文件,需要root权限
- /system/app/
这里存放一些系统的app
- /system/fonts/ 目录
这里存放系统的字体文件
- /system/lib/ 目录
这里存放的几乎是所有的共享库(.so)文件。
- /system/media/ 目录
这里用来保存系统铃声、系统提示音。
storage
storage
目录就是外部存储,包括了机身内部存储和外置SD卡。注意不同的版本存储数据的位置不同,例如:
Androidr4.4.2 带SD卡(没有Android4.4的手机,数据来自网络)
位置 | 路径 | 获取路径的api |
---|---|---|
机身外部存储 | /storage/emulated/0/Android/data/packname/files | getExternalStorageDirectory() |
外置SD卡 | /storage/sdcard1 | getExternalFilesDirs() |
Android 8 小米
位置 | 路径 | 获取路径的api |
---|---|---|
机身外部存储 | /storage/emulated/0/Android/data/packname/files | getExternalStorageDirectory() |
外置SD卡 | /storage/sd_name | getExternalFilesDirs() |
sdcard
详情看Android内、外存储易混淆点剖析(/mnt/sdcard、/storage/sdcard0、/storage/emulated/0等区别)
获取Andorid中的目录
以下api返回的值均为Android O下返回的值
内部储存目录
//创建/data/user/0/packagename/files文件夹,随着应用位置的改变,位置可能改变
context.getFilesDir();
//创建/data/user/0/packagename/cache文件夹当需要空间时,
//系统会自动删除其中的文件(先删除存在最长时间的)
context.getCacheDir();
// 获取 /data 目录
Environment.getDataDirectory()
注意:读写上述的方法返回的文件对象是不用申请权限,当用户卸载app时,系统会删除data/data目录下所有关于该app的文件
外部储存的私有目录
//一般存放临时缓存数据,对应 清除缓存
//目录为 /storage/emulated/0/Android/data/packagename/cache
context.getExternalCacheDir():
/**
*一般放一些长时间保存的数据,对应 清除数据
*type的取值
*null: /storage/emulated/0/Android/data/com.example.androidbase/files
*DIRECTORY_MUSIC *Environment.DIRECTORY_MUSIC时:/storage/emulated/0/Android/data/com.example.androidbase/file*s/Music
* DIRECTORY_PODCASTS
* DIRECTORY_RINGTONES
* DIRECTORY_ALARMS
* DIRECTORY_NOTIFICATIONS
* DIRECTORY_PICTURES
* DIRECTORY_MOVIES
* 自定义字符串:/storage/emulated/0/Android/data/com.example.androidbase/files/自定义字符串
*/
context.getExternalFilesDir(String type):
//使用Environment来获取,需要获取权限来操作
Environment.getExternalStorageDirectory();
方法1、2不需要权限,而方法3需要申请权限,该目录的特点为:
- 系统一般不会清理在里面的文件
- 由于普通用户可能自由操作在里面的文件,使用时应该加个非空判断和异常捕获
- 获取
WRITE_EXTERNAL_STORAGE
的其他应用可以操作该文件,Android 7.0以后要通过FileProvider 访问 - 自Android 4.4开始,App 才可以直接读写外部存储空间中的应用私有目录,使开发人员无需在 Manifest 文件中或者动态申请外部存储空间的文件读写权限。
- 随应用卸载后删除
外部储存的公共目录
/**
* 需要申请权限
* Type的值看上面(不能为null),注意要创建文件时不能使用 File的 mkdir() 和 mkdirs() 方法,它们只会创建目录,可以使用
*createNewFile()或者不使用 都可以创建文件
*空字符串时:/storage/emulated/0
*自定义字符串:/storage/emulated/0/自定义字符串
*/
Environment.getExternalStoragePublicDirectory(String type);
获取外部空间和内部空间总大小和可用大小
Android多媒体数据信息
转载自Android 多媒体:MediaProvider、MediaStore
MediaProvider就是Android系统中的一个数据库,又称多媒体数据库,保存了手机上存储的所有文件的信息。这个数据库存放在/data/data/com.android.providers.media/databases当中,里面有两个数据库:internal.db和external.db,internal.db存放的是系统分区的文件信息,开发者是没法通过接口获得其中的信息的,而external.db存放的则是我们用户能看到的存储区的文件信息,即包含了手机内置存储,还包含了SD卡。
MediaStore提供了在内部和外部存储设备上所有可用媒体的元数据。
MediaStore内部类
- class MediaStore.Audio:所有音频内容的容器
- class MediaStore.Files:MediaProvider表包含媒体存储中所有文件的索引,包括非媒体文件
- class MediaStore.Images:所有图片内容的容器
- interface MediaStore.MediaColumns:MediaProvider表的公共字段
- class MediaStore.Video:所有视频内容的容器
MediaStore.MediaColumns字段说明
- String DATA:磁盘上文件的路径
- String DATE_ADDED:文件添加到media provider的时间(单位秒)
- String DATE_MODIFIED:文件最后一次修改单元的时间
- String DISPLAY_NAME:文件的显示名称
- String HEIGHT:图像/视频的高度,以像素为单位
- String MIME_TYPE:文件的MIME类型
- String SIZE:文件的字节大小
- String TITLE:标题
- String WIDTH:图像/视频的宽度,以像素为单位。
实战
仿QQ本地图片选择器
String[] columns = {MediaStore.Images.Media._ID, MediaStore.Images.Thumbnails.DATA, MediaStore.Images.Media.DATA, MediaStore.Images.Media.BUCKET_ID,
MediaStore.Images.Media.BUCKET_DISPLAY_NAME,MediaStore.MediaColumns.MIME_TYPE,MediaStore.MediaColumns.SIZE
};
String sortOrder = MediaStore.Images.Media.DATE_ADDED+" desc";
Cursor cursor = getActivity().getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, null, null, sortOrder);
LinkedHashMap<String,List<ImageBean>> map = new LinkedHashMap<>();
while (cursor.moveToNext()){
String id = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media._ID));
String thumbnailsPath = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Thumbnails.DATA));
String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
String groupId = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_ID));
String groupName = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME));
String type = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.MIME_TYPE));
String size = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.SIZE));
ImageBean imageBean = new
ImageBean(id,thumbnailsPath,path,groupId,groupName,type,size);
if (map.containsKey(groupId)){
map.get(groupId).add(imageBean);
}else {
ImageGroupBean imageGroupBean = new ImageGroupBean(groupId,groupName,path);
group.add(imageGroupBean);
List<ImageBean> l = new ArrayList<>();
l.add(imageBean);
map.put(groupId,l);
}
}
cursor.close();
效果如图
参考
- https://blog.csdn.net/csdn_aiyang/article/details/80665185
- https://blog.csdn.net/dongyaqin/java/article/details/88947467
- https://blog.csdn.net/qq_39074954/java/article/details/97613088