APP的缓存文件到底应该存在哪?看完这篇文章你应该就自己清楚了

彻底理解android中的内部存储与外部存储

存储在内部还是外部

所有的Android设备均有两个文件存储区域:"internal" 与 "external" 。 这两个名称来自于早先的Android系统,当时大多设备都内置了不可变的(internal storage)及一个类似于SD card这样的可卸载的存储部件(external storage)。之后有一些设备将"internal" 与 "external" 都做成了不可卸载的内置存储,虽然如此,但是这一整块还是从逻辑上有被划分为"internal"与"external"的,只是现在不再以是否可卸载进行区分了。 下面列出了两者的区别:

  • Internal storage:

    • 总是可用的
    • 这里的文件默认只能被我们的app所访问。
    • 当用户卸载app的时候,系统会把internal内该app相关的文件都清除干净。
    • Internal是我们在想确保不被用户与其他app所访问的最佳存储区域。
  • External storage:

    • 这可能是一个移动存储媒体(如一个SD卡)或一个手机内部固定的存储。
    • 并不总是可用的,因为用户有时会通过USB存储模式挂载外部存储器,当取下挂载的这部分后,就无法对其进行访问了。
    • 大家都可以访问的,因此保存在这里的文件可能被其他程序访问。文件保存到外部存储是公开的,可由用户修改他们。
    • 当用户卸载我们的app时,系统仅仅会删除external私有目录(getExternalFilesDir())下的相关文件。
    • External是在不需要严格的访问权限并且希望这些文件能够被其他app所共享或者是允许用户通过电脑访问时的最佳存储区域。

Tip: 尽管app是默认被安装到internal storage的,我们还是可以通过在程序的manifest文件中声明android:installLocation 属性来指定程序安装到external storage。当某个程序的安装文件很大且用户的external storage空间大于internal storage时,用户会倾向于将该程序安装到external storage。更多安装信息见App Install Location

获取External存储的权限

为了写数据到external storage, 必须在你manifest文件中请求WRITE_EXTERNAL_STORAGE权限。

对于internal storage,我们不需要声明任何权限,因为程序默认就有读写程序目录下的文件的权限。

保存到Internal Storage

当保存文件到internal storage时,可以通过执行下面两个方法之一来获取合适的目录作为 FILE 的对象:

  • getFilesDir() : 返回一个File,代表了我们app的internal目录。
  • getCacheDir() : 返回一个File,代表了我们app的internal缓存目录。  请确保这个目录下的文件能够在一旦不再需要的时候马上被删除,并对其大小进行合理限制,例如1MB 。系统的内部存储空间不够时,会自行选择删除缓存文件。

可以使用File() 构造器在那些目录下创建一个新的文件,如下:

File file = new File(context.getFilesDir(), filename);

同样,也可以执行openFileOutput() 获取一个 FileOutputStream 用于写文件到internal目录。如下:

String filename = "myfile";
String string = "Hello world!";
FileOutputStream outputStream; try {
outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
outputStream.write(string.getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}

如果需要缓存一些文件,可以使用createTempFile()。例如:下面的方法从URL中抽取了一个文件名,然后再在程序的internal缓存目录下创建了一个以这个文件名命名的文件。

 public File getTempFile(Context context, String url) {
File file;
try {
String fileName = Uri.parse(url).getLastPathSegment();
file = File.createTempFile(fileName, null, context.getCacheDir());
catch (IOException e) {
// Error while creating file
}
return file;
}

Note: 我们的app的internal storage 目录以app的包名作为标识存放在Android文件系统的特定目录下[data/data/com.example.xx]。 从技术上讲,如果文件被设置为可读的,那么其他app就可以读取该internal文件。然而,其他app需要知道包名与文件名。若没有设置为可读或者可写,其他app是没有办法读写的。因此我们只要使用了MODE_PRIVATE ,那么这些文件就不可能被其他app所访问。

保存文件到External Storage

因为external storage可能是不可用的,比如遇到SD卡被拔出等情况时。因此在访问之前应对其可用性进行检查。我们可以通过执行 getExternalStorageState()来查询external storage的状态。若返回状态为MEDIA_MOUNTED, 则可以读写。示例如下:

 /* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
} /* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
} 外部存储中的文件是可以被用户或者其他应用程序修改的,有两种类型的文件(或者目录):
  • Public files(公共外部存储) :这些文件对与用户与其他app来说是public的,当用户卸载我们的app时,这些文件应该保留。例如,那些被我们的app拍摄的图片视频或者下载的文件。
  • Private files(私有外部存储): 这些文件完全被我们的app所私有,它们应该在app被卸载时删除。尽管由于存储在external storage,那些文件从技术上而言可以被用户与其他app所访问,但实际上那些文件对于其他app没有任何意义。因此,当用户卸载我们的app时,系统会删除其下的private目录。例如,那些被我们的app下载的缓存文件。

想要将文件以public形式保存在external storage中,请使用getExternalStoragePublicDirectory()方法来获取一个 File 对象。当用户卸载我们的app时,这些文件应该保留。这个方法需要带有一个特定的参数来指定这些public的文件类型,以便于与其他public文件进行组织,比如DIRECTORY_MUSIC 或者DIRECTORY_PICTURES. 例如:

public File getAlbumStorageDir(String albumName) {
// Get the directory for the user's public pictures directory.
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), albumName);
if (!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
return file;
}

想要将文件以private形式保存在external storage中,可以通过执行getExternalFilesDir() 来获取相应的目录,并且传递一个指示文件类型的参数。Each directory created this way is added to a parent directory that encapsulates all your app's external storage files, which the system deletes when the user uninstalls your app.如下示例:

public File getAlbumStorageDir(Context context, String albumName) {
// Get the directory for the app's private pictures directory.
File file = new File(context.getExternalFilesDir(
Environment.DIRECTORY_PICTURES), albumName);
if (!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
return file;
}

如果刚开始的时候,没有预定义的子目录存放我们的文件,可以在 getExternalFilesDir()方法中传递null. 它会返回app在external storage下的private的根目录。

请记住,getExternalFilesDir() 方法创建的目录会在app被卸载时被系统删除。如果我们的文件想在app被删除时仍然保留,请使用getExternalStoragePublicDirectory().

无论是使用 getExternalStoragePublicDirectory() 来存储可以共享的文件,还是使用 getExternalFilesDir() 来储存那些对于我们的app来说是私有的文件,有一点很重要,那就是要使用那些类似DIRECTORY_PICTURES 的API的常量。那些目录类型参数可以确保那些文件被系统正确的对待。例如,那些以DIRECTORY_RINGTONES 类型保存的文件就会被系统的media scanner认为是ringtone而不是音乐。

Note: 如果你将你的图片或者视频等存储在getExternalFilesDir())提供的目录(app私有)中,媒体扫描器(media scanner)不能访问到你的文件,因为它们是你的app私有的。

查询剩余空间

如果事先知道想要保存的文件大小,可以通过执行getFreeSpace() or getTotalSpace() 来判断是否有足够的空间来保存文件,从而避免发生IOException。那些方法提供了当前可用的空间还有存储系统的总容量。

然而,系统并不能保证可以写入通过getFreeSpace()查询到的容量文件, 如果查询的剩余容量比我们的文件大小多几MB,或者说文件系统使用率还不足90%,这样则可以继续进行写的操作,否则最好不要写进去。

Note:并没有强制要求在写文件之前去检查剩余容量。我们可以尝试先做写的动作,然后通过捕获 IOException 。这种做法仅适合于事先并不知道想要写的文件的确切大小。例如,如果在把PNG图片转换成JPEG之前,我们并不知道最终生成的图片大小是多少。

删除文件

在不需要使用某些文件的时候应删除它。删除文件最直接的方法是直接执行文件的delete()方法。

myFile.delete();

如果文件是保存在internal storage,我们可以通过Context来访问并通过执行deleteFile()进行删除

myContext.deleteFile(fileName);

Note: 当用户卸载我们的app时,android系统会删除以下文件:

  • 所有保存到internal storage的文件。
  • 所有使用getExternalFilesDir()方式保存在external storage的文件。

然而,通常来说,我们应该手动删除所有通过 getCacheDir() 方式创建的缓存文件,以及那些不会再用到的文件。

 
 

APP的缓存文件到底应该存在哪?看完这篇文章你应该就自己清楚了的更多相关文章

  1. [转帖]看完这篇文章你还敢说你懂JVM吗?

    看完这篇文章你还敢说你懂JVM吗? 在一些物理内存为8g的服务器上,主要运行一个Java服务,系统内存分配如下:Java服务的JVM堆大小设置为6g,一个监控进程占用大约 600m,Linux自身使用 ...

  2. [转帖]看完这篇文章,我奶奶都懂了https的原理

    看完这篇文章,我奶奶都懂了https的原理 http://www.17coding.info/article/22 非对称算法 以及 CA证书 公钥 核心是 大的质数不一分解 还有 就是 椭圆曲线算法 ...

  3. 【转】APP的缓存文件到底应该存在哪?看完这篇文章你应该就自己清楚了

    只要是需要进行联网获取数据的APP,那么不管是版本更新,还是图片缓存,都会在本地产生缓存文件.那么,这些缓存文件到底放在什地方合适呢?系统有没有给我们提供建议的缓存位置呢?不同的缓存位置有什么不同呢? ...

  4. 如果你每次面试前都要去背一篇Spring中Bean的生命周期,请看完这篇文章

    前言 当你准备去复习Spring中Bean的生命周期的时候,这个时候你开始上网找资料,很大概率会看到下面这张图: 先不论这张图上是否全面,但是就说这张图吧,你是不是背了又忘,忘了又背? 究其原因在于, ...

  5. 细心看完这篇文章,刷新对Javascript Prototype的理解

    var person={name:'ninja'}; person.prototype.sayName=function(){ return this.name; } 分析上面这段代码,看看有没有问题 ...

  6. 看完这篇文章,我奶奶都懂了https的原理

    本文在个人技术博客同步发布,详情可猛戳 亦可扫描屏幕右方二维码关注个人公众号 Http存在的问题   上过网的朋友都知道,网络是非常不安全的.尤其是公共场所很多免费的wifi,或许只是攻击者的一个诱饵 ...

  7. Python正则表达式,看完这篇文章就够了...#华为云·寻找黑马程序员#【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  8. flutter系列之:flutter架构什么的,看完这篇文章就全懂了

    目录 简介 Flutter的架构图 embedder engine Flutter framework Widgets Widgets的可扩展性 Widgets的状态管理 渲染和布局 总结 简介 Fl ...

  9. 看完这篇文章,我奶奶都知道什么是JVM中的内存模型与垃圾回收!

    扩展阅读:JVM从入门开始深入每一个底层细节 六.内存模型 6.1.内存模型与运行时数据区 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干不同数据区域. Java内存模型的主要目 ...

随机推荐

  1. zoj 1610

    Count the Colors Time Limit: 2 Seconds      Memory Limit: 65536 KB Painting some colored segments on ...

  2. samsung Galaxy s2(GT i9100g )刷机升级至4.4小记

    从昨天上午到现在,大部分时间都是在将i9100g更新到4.4.虽然中途也做了一些别的事情,但是更新过程还是走了一点弯路,比开始预想的稍微慢了一点,现在将完整的更新步骤分享给大家,以帮助后来的同学.升级 ...

  3. centos7 安装拼音输入法(转载)

    http://m.blog.csdn.net/article/details?id=52137523

  4. ASP.NET MVC铵钮Click后下载文件

    本篇Insus.NET练习的是FilePathResult和FileStreamResult操作.本篇也算是<如何把Json格式字符写进text文件中>http://www.cnblogs ...

  5. 设置apache https服务

    配置http.conf,所在位置d:\wamp\bin\apache\apache2.4.9\conf\http.conf   LoadModule socache_shmcb_module modu ...

  6. [转]JS调用Android里面的方法,Android调用JS里面的方法

    FROM : http://blog.csdn.net/hj563308597/article/details/45197709 Android WebView 在公司Android的开发过程中遇到一 ...

  7. KindEditor得不到textarea值的解决方法

    转自:http://blog.phpha.com/archives/510.html 以前有朋友遇到过这个问题,就是KindEditor在火狐下或者其他浏览器下都无法得到textarea文本框的值,点 ...

  8. 全球第一本基于Bootstrap V3.x的图书《深入理解Bootstrap》终于上市了,再次免费送书15本【活动结束】

    先说活动规则,再说书的事 经过将近1年的努力,终于有了第一本自己独立编写的书:<深入理解Bootstrap>,基于最新版V 3.1 ,侧重于源码详解.架构分析.插件扩展(全新开发)实战.为 ...

  9. caffe的python接口学习(1):生成配置文件

    caffe是C++语言写的,可能很多人不太熟悉,因此想用更简单的脚本语言来实现.caffe提供matlab接口和python接口,这两种语言就非常简单,而且非常容易进行可视化,使得学习更加快速,理解更 ...

  10. ASP.NET XmlSerializer权限问题

    今天碰到一个奇怪问题.因为在2台服务器上做文件共享,使服务器A能访问服务器B的共享目录.在IIS上使用虚拟目录实现的话,需要给应用程序池指定一个统一的账号.在调试的时候能够使用,但是一部署到服务器上, ...