先简要介绍一下Android系统的文件系统吧,本文基于原生Android M系统:

我们都知道Android系统内核就是个Linux、所以我们的文件系统与Linux也是基本一致的,最顶部的目录是 “/” 接下来就是 一些文件或者文件夹,如下图:

/

├── acct

│ └── uid

│ ├── cpuacct.stat

│ └── ...

├── cache

│ ├── backup

│ │ ├── cpuacct.stat

│ │ └── ...

│ ├── lost+found

│ │ └── ...

│ ├── cpuacct.stat

│ │ └── ...

│ └── recovery

│ └── ...

├── ...

├── storage

│ ├── emulated

│ │ ├── 0

│ │ │ ├── Alarms

│ │ │ ├── Android

│ │ │ ├── backups

│ │ │ ├── DCIM

│ │ │ └── ...

│ │ │

│ │ └── obb

│ │

│ └── self

│ └── primary

│ ├── Alarms

│ └── ...

├── system

一:当然上面的有一些目录是系统级的,也就是用户是没有权限查看的(手机有root权限的话你就可以访问所有的目录了)。这里我们说一说在平常开发中经常使用到的目录,其他的有需要可以去了解一下。

应用程序的私有目录,用户无法查看,app一安装系统会自动创建 app一卸载系统也会立即删除

/data/data/packageName/
用户可以操作的文件目录
/storage/emulated/0/

二:Android 为我们提供了一系列API来获取我们需要的存储目录,如下:

Environment.getExternalStorageDirectory().getPath();
/storage/emulated/0
getExternalCacheDir().getPath();
/storage/emulated/0/Android/data/com.azhon.androiddir/cache
getCacheDir().getPath();
/data/user/0/com.azhon.androiddir/cache
getFilesDir().getPath();
/data/user/0/com.azhon.androiddir/files
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
/storage/emulated/0/Music
type 还可以取不同的值…
/*
* @param type The type of storage directory to return. Should be one of
* {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS},
* {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS},
* {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES},
* {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS},
* {@link #DIRECTORY_DCIM}, or {@link #DIRECTORY_DOCUMENTS}. May not be null.
* @return Returns the File path for the directory. Note that this directory
* may not yet exist, so you must make sure it exists before using
* it such as with {@link File#mkdirs File.mkdirs()}.
*/
public static File getExternalStoragePublicDirectory(String type) {
throwIfUserRequired();
return sCurrentUser.buildExternalStoragePublicDirs(type)[0];
}

三:在这里一直没有找到怎么获取/data/data/packageName/目录,网上大部分都说是用getFilesDir()然而我获取到的路径在上面已经给出了,完全不一样。那我们要怎么获取那个路径呢?答案当然是直接写喽(反正是固定的)

缓存目录
/data/data/packageName/cache
数据库目录
/data/data/packageName/databases
文件存储目录
/data/data/packageName/files
SharedPreferences文件存储目录
/data/data/packageName/shared_prefs
……

四:接下来就是本文的重点了,我们都知道往手机上写入一个文件需要 [存储空间] 权限,在Android M之后 还需要动态申请权限。那么重点来了,当我们往App的缓存目录中写入一个文件 也就是/storage/emulated/0/Android/data/com.azhon.androiddir/cache目录它是不需要声明权限的 对的 你没看错是不需要权限的下面我们来试下:

在Android 应用根目录下生成唯一id_Android

public void writeToCache(View view) {
String externalCacheDir = getExternalCacheDir().getPath();
File file = new File(externalCacheDir, "test.txt");
try {
FileOutputStream stream = new FileOutputStream(file);
for (int i = 0; i < 66; i++) {
stream.write("Hello world!
".getBytes());
}
stream.flush();
stream.close();
Toast.makeText(this, "写入成功!", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
}

前往文件管理器查看一下,是存在的。

在Android 应用根目录下生成唯一id_android 根目录缓存_02

这里需要注意的是:这个目录用户是可以访问到的所以这个里的文件是有可能会被用户删除的,所以在用的时候得考虑好;如果你想不被清除那么就需要保存到/data/data/packageName/下了。

当app被卸载后这个文件夹也会被系统自动删除

往/data/data/packageName/目录下写入一个文件,也是不需要权限的。

public void writeToData(View view) {
File dir = new File("/data/data/" + getPackageName() + "/files");
if (!dir.exists()) {
dir.mkdirs();
}
File file = new File(dir.getPath(), "test.txt");
try {
FileOutputStream stream = new FileOutputStream(file);
for (int i = 0; i < 66; i++) {
stream.write("Hello Android!
".getBytes());
}
stream.flush();
stream.close();
Toast.makeText(this, "写入成功!", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
}

五:在系统设置——应用——对应的app——存储空间,这里可以看到我们app所占用的磁盘空间 和清理空间

在Android 应用根目录下生成唯一id_androidd_03

这里的清除缓存按钮对应的就是清除我们getExternalCacheDir().getPath()目录下的所有文件

清除数据 就是清除我们/data/data/packageName/目录下的所有文件,同时也会清空getExternalCacheDir().getPath()目录下的所有文件

所以我们app内经常写到的一个清除缓存功能,现在就知道要怎么写了: public void clearCache(View view) {

File externalCacheDir = getExternalCacheDir();
deleteDirFile(externalCacheDir);
Toast.makeText(this, "清除缓存成功!", Toast.LENGTH_SHORT).show();
}
/** * 删除指定目录下文件及目录 */
public static void deleteDirFile(File file) {
if (file.isDirectory()) {
// 如果下面还有文件
File[] files = file.listFiles();
for (File f : files) {
deleteDirFile(new File(f.getPath()));
}
}
if (file.isDirectory()) {
// 目录
if (file.listFiles().length == 0) {
// 目录下没有文件或者目录,删除
file.delete();
}
} else {
// 如果是文件,删除
file.delete();
}
}
而不是写个这样的清除缓存
public void clearCache(View view) {
try {
Thread.sleep(666);
} catch (InterruptedException e) {
e.printStackTrace();
}
Toast.makeText(this, "清除缓存成功!", Toast.LENGTH_SHORT).show();
}
}

六:总结 当我们使用到文件存储时如:app版本更新的时候apk存放的目录就可以使用缓存目录了,这样不需要权限也可以写入,开发省心、用户也方便(^-^) Demo下载地址在这里