目录
写在前面
Android有五种主要存储方式的用法,包括
下面,我们将要讲解一下SD卡文件,在讲解SD卡文件之间,我们先来看看Android的存储目录。
1. Android的存储目录
存储规则:
- 首先,需要明确的是,手机的存储空间一般分为两块,一块用于
内部存储
,另一块用于外部存储(SD卡)
。早期的SD卡是可插拔式的存储芯片,而如今的手机把SD卡固化到手机内部,虽然拔不出来,但是Android仍然称之为外部存储。 - Android从7.0开始加强了SD卡的权限管理,即使App声明了完整的SD卡操作权限,系统仍然默认禁止该App访问外部存储。不过系统默认关闭存储其实只是关闭
外部存储的公共空间
,外部存储的私有空间
依然可以正常读写,即Android/data
。
1.1 内部存储
- 定义
- 内部存储:是指每个
app应用内部私有
的存储空间, 比如SharedPreference
存储的数据、Sqlite
存储的数据、以及缓存数据
等等都是放在内部存储空间里面。
- 内部存储:是指每个
- 特点:
- 应用私有,不能被其他程序访问。
- 随着应用的安装而创建,随着应用的卸载而删除。
默认不可见
(你在文件管理中看不到它)
路径形式:
/data/app/
/data/data/app包名/shared_prefs
/data/data/app包名/cache
/data/data/app包名/databases
/data/data/app包名/files
1.2 外部存储
- 定义
- 即SD卡
- 又分为:公有目录(空间)和私有目录(空间)
- 为什么SD卡会分公有和私有?
- 解释:
内部存储
保存着每个应用的安装目录,但是安装目录的空间是很紧张的,所以Android在SD卡的“Android/data”
目录下给每个应用又单独建了一个文件目录,用于给应用保存自己需要处理的临时文件
。 - 这个给每个应用单独建立的文件目录,只有当前应用才能够读写文件,其他应用是不允许进行读写的,故而“Android/data”目录算是外部存储上的私有空间。
另外,
- 解释:
公有空间 | 私有空间 |
---|---|
所有应用均可访问 | 只有应用自己才可以访问 |
默认情况下是不存在的,需要程序员自行创建 |
2. 内部存储文件操作→Context
获取手机的内部存储信息通过Context
类实现
方法 | 路径 |
---|---|
getDataDir | /data/data/0/app包名 |
getFilesDir | /data/data/app包名/files |
getCacheDir | /data/data/0/app包名/cache |
getSharedPreferences() | /data/data/app包名/shared_prefs目录 |
注意:
/data/data/
在其它手机有可能为/data/user/
等目录
3. 外部存储文件操作→(SD卡)
3.1 公共空间(目录)操作→Environment
获取手机上的SD卡信息通过Environment
类实现,该类是App获取各种目录信息的工具;
获取系统存储目录
- getRootDirectory:获得系统根目录的路径。
/system
- getDataDirectory:获得系统数据目录的路径。
/data
- getDownloadCacheDirectory:获得下载缓存目录的路径。
/cache
获取外部存储(SD Card)的公共空间
getExternalStorageState
:获得SD卡的状态。其状态包括:
常量 | 解释:返回getExternalStorageState() |
---|---|
MEDIA_BAD_REMOVAL | SDCard 被卸载前己被移除 |
MEDIA_CHECKING | 正在检查存储媒体 |
MEDIA_MOUNTED | SD Card存在,且具有读/写权限 |
MEDIA_MOUNTED_READ_ONLY | SD Card权限为只读 |
MEDIA_NOFS | 不支持的文件系统(SD卡格式不对) |
MEDIA_REMOVED | SDCard已经移除 |
MEDIA_SHARED | 当期 SDCard 未安装 ,但可通过 USB 存储共享 |
MEDIA_UNMOUNTABLE | SDCard 无法安装 |
MEDIA_UNMOUNTED | 返回 SDCard 已卸掉假设 SDCard 是存在可是没有被安装 |
- getExternalStoragePublicDirectory:获得SD卡指定类型目录的路径。
Environment类的目录类型 | 常量值 | 常量说明 |
---|---|---|
DIRECTORY_DCIM | DCIM | 相片存放目录(包括相机拍摄的图片和视频) |
DIRECTORY_DOCUMENTS | Documents | 文档存放目录 |
DIRECTORY_DOWNLOADS | Download | 下载文件存放目录 |
DIRECTORY_MOVIES | Movies | 视频存放目录 |
DIRECTORY_MUSIC | Music | 音乐存放目录 |
DIRECTORY_PICTURES | Pictures | 图片存放目录 |
- getStorageState:获得指定目录的状态
- getExternalStorageDirectory:获得外部存储(SD卡)的根路径。
/storage/emulated/0/
// 获取系统的公共存储路径
String publicPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString();
系统的公共存储路径:/storage/emulated/0/Download
3.2 私有空间(目录)操作→Context
上面我们讲过了使用Context来获取内部存储,下面我们将讲解如何使用Context来获取外部存储的私有空间
// 获取当前App的私有存储路径
String privatePath = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString();
当前App的私有存储路径:/storage/emulated/0/Android/data/com.example.storage/files/Download
获取外部存储(SD Card)的私有空间
方法 | 路径 |
---|---|
getExternalCacheDir() | /storage/emulated/0/Android/data/<应用包名>/cache |
getExternalFilesDir(null) | /storage/emulated/0/Android/data/<应用包名>/files |
getExternalFilesDir("") | /storage/emulated/0/Android/data/<应用包名>/files |
getExternalFilesDir(“logs”) | /storage/emulated/0/Android/data/<应用包名>/files/logs |
getExternalFilesDir(“logs/zip”) | /storage/emulated/0/Android/data/<应用包名>/files/logs/zip |
getExternalFilesDir() | 路径 |
---|---|
getExternalFilesDir(Environment.DIRECTORY_MUSIC); | /storage/emulated/0/Android/data/包名/files/Music |
getExternalFilesDir(Environment.DIRECTORY_PODCASTS); | /storage/emulated/0/Android/data/包名/files/Podcasts |
getExternalFilesDir(Environment.DIRECTORY_RINGTONES); | /storage/emulated/0/Android/data/包名/files/Ringtones |
getExternalFilesDir(Environment.DIRECTORY_ALARMS); | /storage/emulated/0/Android/data/包名/files/Alarms |
getExternalFilesDir(Environment.DIRECTORY_NOTIFICATIONS); | /storage/emulated/0/Android/data/包名/files/Notifications |
getExternalFilesDir(Environment.DIRECTORY_PICTURES); | /storage/emulated/0/Android/data/包名/files/Pictures |
getExternalFilesDir(Environment.DIRECTORY_MOVIES); | /storage/emulated/0/Android/data/包名/files/Movies |
4 StatFs 类
- StatFs 一个模拟linux的df命令的一个类,获得SD卡和手机内存的使用情况
4.1 StatFs 常用方法:
- getAvailableBlocks()
- 解释:返回 Int 。获取当前可用的存储空间
- getBlockCount()
- 解释:返回 Int ,获取该区域可用的文件系统数
- getBlockSize()
- 解释:返回 Int ,大小,以字节为单位,一个文件系统
- getFreeBlocks()
- 解释:返回 Int ,该块区域剩余的空间
- restat(String path)
- 解释:运行一个由该对象所引用的文件系统
4.2 工具类
在存储文件时,为了保证有充足的剩余空间大小,通常须要知道系统内部或者sdcard的存储大小。以下提供一个工具类
package com.neverno.util;
import java.io.File;
import android.os.Environment;
import android.os.StatFs;
public class MemoryStatus {
static final int ERROR = -1;
// 外部存储是否可用
static public boolean externalMemoryAvailable() {
return android.os.Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA\_MOUNTED);
}
// 获取手机内部可用空间大小
static public long getAvailableInternalMemorySize() {
File path = Environment.getDataDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long availableBlocks = stat.getAvailableBlocks();
return availableBlocks \* blockSize;
}
// 获取手机内部空间大小
static public long getTotalInternalMemorySize() {
File path = Environment.getDataDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long totalBlocks = stat.getBlockCount();
return totalBlocks \* blockSize;
}
// 获取手机外部可用空间大小
static public long getAvailableExternalMemorySize() {
if (externalMemoryAvailable()) {
File path = Environment.getExternalStorageDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long availableBlocks = stat.getAvailableBlocks();
return availableBlocks \* blockSize;
} else {
return ERROR;
}
}
// 获取手机外部空间大小
static public long getTotalExternalMemorySize() {
if (externalMemoryAvailable()) {
File path = Environment.getExternalStorageDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long totalBlocks = stat.getBlockCount();
return totalBlocks \* blockSize;
} else {
return ERROR;
}
}
static public String formatSize(long size) {
String suffix = null;
if (size >= 1024) {
suffix = "KiB";
size /= 1024;
if (size >= 1024) {
suffix = "MiB";
size /= 1024;
}
}
StringBuilder resultBuffer = new StringBuilder(Long.toString(size));
int commaOffset = resultBuffer.length() - 3;
while (commaOffset > 0) {
resultBuffer.insert(commaOffset, ',');
commaOffset -= 3;
}
if (suffix != null)
resultBuffer.append(suffix);
return resultBuffer.toString();
}
}
5. 小结
最后,一幅图来简单说明一下Android的存储目录和获取方法