一、基本认识
所有的Android设备都有两个文件存储区域:“内部”和“外部”存储。这两个名称来自早期的Android,当时大多数设备都提供内置的固定的内存(内部存储)即ROM(主要分三部分:系统存储、系统缓存、内部存储)中的内部存储部分,外加一个可移动的存储介质,如SD卡(外部存储)。现在的大部分设备把固定不变的存储空间分成“内部”和“外部”两部分,这样即使没有可移动的存储介质,也总会有两个存储空间,并且不管外部存储器是可移动的,还是固定的,API的行为是相同的。
把手机连接电脑,能被电脑识别的部分就一定是外部存储。
打开DDMS,有一个File Explorer,如下:

这里有三个文件夹需要我们重视,一个是data,一个是mnt,一个是storage,我们下面就详细说说这三个文件夹。
1、内存(Memory)
RAM(随机访问存储器),断电后资料丢失。
2、内部存储(InternalStorage)
data文件夹就是内部存储,应用程序私有的,其他应用无法访问。当我们打开data文件夹之后(没有root的手机不能打开该文件夹),里边有两个文件夹值得我们关注,如下:

app文件夹:存放着我们所有安装的app的apk文件。当我们调试一个app的时候,可以看到控制台输出的内容,有一项是uploading……就是上传我们的apk到这个文件夹,上传成功之后才开始安装。
data文件夹:这个文件夹里边都是一些包名,打开这些包名之后我们会看到这样的一些文件:
- /data/data/包名/shared_prefs
- /data/data/包名/databases
- /data/data/包名/files
- /data/data/包名/cache
在使用sharedPreferenced的时候,将数据持久化存储于本地,就是将xml文件存储于shared_prefs文件夹;App里边的数据库文件就存储于databases文件夹中;普通数据存储在files中;缓存文件存储在cache文件夹中。
方法
-
Environment.getDataDirectory()
/data -
context.getFilesDir()
/data/data/包名/files -
context.getCacheDir()
/data/data/包名/cache,机身内存不足时,文件会被删除
3、外部存储(ExternalStorage)
任何有访问权限的应用均可以访问修改,相对于设备的内部存储空间而言,会大很多,所以一般比较大的数据,均会存放在外部存储中。写入数据,你必须在清单文件中申请WRITE_EXTERNAL_STORAGE权限和READ_EXTERNAL_STORAGE(API 19开始,不再需要显式声明这两个权限,除非要读写其他应用的应用数据)。外部存储一般就是我们上面看到的storage文件夹,当然也有可能是mnt文件夹,这个不同厂家有可能不一样。
一般来说,在storage文件夹中有一个sdcard文件夹,这个文件夹中的文件又分为两类,一类是公有目录,还有一类是私有目录,其中的公有目录有九大类,比如DCIM、DOWNLOAD等这种系统为我们创建的文件夹,私有目录就是Android这个文件夹,这个文件夹打开之后里边有一个data文件夹,打开这个data文件夹,里边有许多包名组成的文件夹(也可以被其他应用修改)。
建议App的数据应该存储在外部存储的私有目录中该app的包名下,这样当用户卸载掉App之后,相关的数据会一并删除,这样有利于系统维护,也避免用户的反感。如果你直接在/storage/sdcard目录下创建了一个应用的文件夹,那么当你删除应用的时候,这个文件夹就不会被删除。不建议往内部存储中写太多的数据,毕竟空间有限。
按照路径的特征,又可以将文件存储的路径分为两大类:路径中含有包名的;路径中不含有包名的。含有包名的路径,因为和某个App有关,所以对这些文件夹的访问都是调用Context里边的方法,而不含有包名的路径,和某一个App无关,可以通过Environment中的方法来访问。
打开手机设置,选择应用管理,选择任意一个App,然后你会看到两个按钮,一个是清除缓存,另一个是清除数据。清除数据清除的是内部存储目录中相应的files和cache文件夹中的文件和外部存储中相应的files和cache文件夹中的文件。
方法:
-
Environment.getExternalStorageState() String
获取SD卡状态,Environment.MEDIA_MOUNTED为可用 -
Environment.getExternalStorageDirectory()
获取外部存储根目录(/storage/sdcard0) -
Environment.getExternalStoragePublicDirectory("folder1")
/storage/sdcard0/folder1 -
Environment.getExternalStoragePublicDirectory(String type)
访问公有九大目录 -
File getExternalFilesDir(String type)
/storage/sdcard/Android/包名/files -
File getExternalCacheDir()
/storage/sdcard/Android/包名/cache -
getExternalFilesDir(null)
/storage/Android/data/包名/files -
getExternalFilesDir("caches")
/storage/Android/data/包名/files/caches,当空间不足时,文件不会实时被删除,可能返回空对象
type类型:
值 | 文本 |
---|---|
Environment.DIRECTORY_NOTIFICATIONS | Notifications |
Environment.DIRECTORY_PODCASTS | Podcasts |
Environment.DIRECTORY_RINGTONES | Ringtones |
Environment.DIRECTORY_ALARMS | Alarms |
Environment.DIRECTORY_PICTURES | Pictures |
Environment.DIRECTORY_MOVIES | Movies |
Environment.DIRECTORY_DOWNLOADS | Download |
Environment.Environment.DIRECTORY_DCIM | DCIM |
Environment.DIRECTORY_DOCUMENTS | Documents |
二、StatFs
用于获取存储空间
- 构造函数
StatFs(String filePath)
API<18
-
getAvailableBlocks()
文件系统中可被应用程序使用的空闲存储区块的数量 -
getBlockCount()
文件系统中总的存储区块的数量 -
getBlockSize()
文件系统中每个存储区块的字节数 -
getFreeBlocks()
文件系统中总的空闲存储区块的数量,包括保留的存储区块(不能被普通应用程序使用)
API>=18
-
getAvailableBlocksLong()
文件系统中可被应用程序使用的空闲存储区块的数量 -
getAvailableBytes()
文件系统中可被应用程序使用的空闲字节数 -
getBlockCountLong()
文件系统中总的存储区块的数量 -
getBlockSizeLong()
文件系统中每个存储区块的字节数 -
getFreeBlocksLong()
文件系统中总的空闲存储区块的数量,包括保留的存储区块(不能被普通应用程序使用) -
getFreeBytes()
文件系统中总的空闲字节数,包括保留的存储区块(不能被普通应用程序使用) -
getTotalBytes()
文件系统支持的总的存储字节数
获取SD卡的完整空间大小,返回MB
StatFs fs = new StatFs(getSDCardBaseDir());
long count = fs.getBlockCountLong();
long size = fs.getBlockSizeLong();
return count * size / 1024 / 1024;
往SD卡的公有目录下保存文件
public static boolean saveFileToSDCardPublicDir(byte[] data, String type, String fileName) {
BufferedOutputStream bos = null;
if (isSDCardMounted()) {
File file = Environment.getExternalStoragePublicDirectory(type);
try {
bos = new BufferedOutputStream(new FileOutputStream(new File(file, fileName)));
bos.write(data);
bos.flush();
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return false;
}
从SD卡获取文件
public static byte[] loadFileFromSDCard(String fileDir) {
BufferedInputStream bis = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
bis = new BufferedInputStream(new FileInputStream(new File(fileDir)));
byte[] buffer = new byte[8 * 1024];
int c = 0;
while ((c = bis.read(buffer)) != -1) {
baos.write(buffer, 0, c);
baos.flush();
}
return baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
baos.close();
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
参考文献:
彻底理解android中的内部存储与外部存储
是时候弄清楚getExternalStorageDirectory()和getExternalFilesDir()的区别了
Android文件存储使用参考 - liaohuqiu
网友评论