在所有的Android手机中,文件存储空间都分为两部分:①手机内置(internal)的,不可卸载的;②外置(external)的可卸载的SD卡。不过随着手机的发展,有些厂商生产的设备将“internal”和“external”都做成了不可卸载的内置存储。在实际开发中文件到底应该存储到哪里,怎么存储经常会困扰我们,笔者为了彻底弄清楚这个问题,就查看了Android官方网站的相关资料,并翻译如下(有译的不好的请指教),为了便于大家阅读,将重要的原文段落附上:

Choose Internal or External Storage(选择内置存储还是外置存储)

All Android devices have two file storage areas: "internal" and "external" storage. These names come from the early days of Android, when most devices offered built-in non-volatile memory (internal storage), plus a removable storage medium such as a micro SD card (external storage). Some devices divide the permanent storage space into "internal" and "external" partitions, so even without a removable storage medium, there are always two storage spaces and the API behavior is the same whether the external storage is removable or not. The following lists summarize the facts about each storage space.

译:所有的 Android 设备都有两个文件存储区域:内置的(internal)和外置的(external)存储区域。这两个名称来源于早期版本的Android系统,当时大多数设备提供了 内置的不可变的内存(internal storage),外加一个可卸载的外部存储媒介(external storage),就像SD卡这样的媒介。之后一些设备提供了永久的存储空间并将其分为 “internal” 和 “external” 两部分,虽然没有了可拆卸的存储介质,但是存储介质任然分为两个存储空间,并且API 的行为不会因为外部存储是否可拆卸而有所不同(意思就是API操作是相同的)。下面的列表总结了两者之间的差异:

Internal storage:

  • It's always available.(总是可用的)
  • Files saved here are accessible by only your app by default.(这里的文件默认只能被我们的 app所访问)
  • When the user uninstalls your app, the system removes all your app's files from internal storage.(当用户卸载app 的时候,系统会将internal内该app的文件清除干净)
  • Internal storage is best when you want to be sure that neither the user nor other apps can access your files.(当你想确保不管是用户还是其他的app都无法访问你的文件时存储在internal是最好的)

External storage:

  • It's not always available, because the user can mount the external storage as USB storage and in some cases remove it from the device.(并不总是可用的,因为在有些情景下用户可以通过USB存储模式挂载外部存储器,此时便无法访问了)
  • It's world-readable, so files saved here may be read outside of your control.(是大家都可以访问的,所以文件存储在这可以被其他程序访问而不受你的控制)
  • When the user uninstalls your app, the system removes your app's files from here only if you save them in the directory from getExternalFilesDir().(当用户卸载app时,系统仅仅会清除通过getExternalFilesDir().方法得到的根目录下与app相关的文件)

External storage is the best place for files that don't require access restrictions and for files that you want to share with other apps or allow the user to access with a computer.(外部存储是存储不需要访问限制条件的文件以及你想与其他app共享文件或者允许用户通过电脑访问文件的最佳存储区域)
























提示:尽管应用程序(app)默认安装在内置存储中,你可以在清单文件(mainifest.xml)中指定android:installLocation 属性来将我们的app安装到外置存储(external storage)中。当我们的apk文件过大,而且外置存储又比内置存储大时,这个选项会对我们非常有用。

Obtain Permissions for External Storage(获取外部存储权限)

To write to the external storage, you must request the  WRITE_EXTERNAL_STORAGE  permission in your  manifest file :

译:为写数据到外置存储,我们必须清单文件(manifest)中请求WRITE_EXTERNAL_STORAGE 权限。

        ...

Caution:  Currently, all apps have the ability to read the external storage without a special permission. However, this will change in a future release. If your app needs to read the external storage (but not write to it), then you will need to declare the  READ_EXTERNAL_STORAGE  permission. To ensure that your app continues to work as expected, you should declare this permission now, before the change takes effect.

译:注意:当前,所有app拥有读取external  storage的能力而不需要指定权限。然而,这将会将来发布的版本中有所改变。如果我们的app需要读取external  storage(但是不去写入数据时),这个时候你需要声明READ_EXTERNAL_STORAGE 这个权限。为了确保你的app能够持续的正常运行,在未来的版本修改生效之前,你还是应该声明这个读权限。

        ...
然而,如果你的app使用了 WRITE_EXTERNAL_STORAGE这个权限,它同时也暗示了你拥有读外置存储的 权限。

对于保存文件到internal  storage,你不需要任何权限。我们的应用程序拥有在内置存储目录下读写文件的权利。

Save a File on Internal Storage(保存文件到Interanl Storage)

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

getFilesDir() Returns a  File representing an internal directory for your app.(译:返回一个代表了我们app的internal 目录) getCacheDir() Returns a  File representing an internal directory for your app's temporary cache files. Be sure to delete each file once it is no longer needed and implement a reasonable size limit for the amount of memory you use at any given time, such as 1MB. If the system begins running low on storage, it may delete your cache files without warning.(译:返回一个代表我们app的在internal里的临时缓存目录。请确保这个目录下的文件一旦你不再需要时马上删除,并根据你在某个时间要使用的存储空间大小设置一个合理的限制,比如1M。如果系统开始运行缓慢,它会删除我们的缓存文件,连一个警告都不会有) To create a new file in one of these directories, you can use the  File()  constructor, passing the  File  provided by one of the above methods that specifies your internal storage directory. For example:(译:想在这其中的一个目录中创建一个新的文件,你可以使用  File() 构造器,传入的 File 参数由上面的某一个方法指定的内置存储目录。例如:)

File file = new File(context.getFilesDir(), filename);
Alternatively, you can call  openFileOutput()  to get a  FileOutputStream  that writes to a file in your internal directory. For example, here's how to write some text to a file:(二者择一的,你可以调用openFileOutput()方法去获取一个  FileOutputStream 对象,这个对象写数据到internal  directory的一个文件,例如,如何写一些文本到一个文件:
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();}
Or, if you need to cache some files, you should instead use  createTempFile() . For example, the following method extracts the file name from a  URL  and creates a file with that name in your app's internal cache directory:(译:或者你想缓存一些文件,你应该使用 createTempFile() 方法来代替。例如,下面的方法从一个 URL 提取文件名 并且在你的app的内置缓存目录中新建一个以这个名字为文件名的文件):

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:  Your app's internal storage directory is specified by your app's package name in a special location of the Android file system. Technically, another app can read your internal files if you set the file mode to be readable. However, the other app would also need to know your app package name and file names. Other apps cannot browse your internal directories and do not have read or write access unless you explicitly set the files to be readable or writable. So as long as you use  MODE_PRIVATE  for your files on the internal storage, they are never accessible to other apps. 译:注释:你的app的内置存储目录在Android文件系统中的一个确定的位置并且由你的app 的包名来指定。从技术上讲,如果你的文件设置为可读模式,其他的app可以读取你的internal文件。然而,其他的app 需要知道你的app的包名以及文件名。其他的app 不能浏览你的internal 目录,没有读写访问权限除非你明确设置文件是可读或者可写的。所以只要你为你的存储在internal  storage(内置存储)中的文件使用  MODE_PRIVATE  模式,那么它们对于其他的app永远也不会有访问权限。

Save a File on External Storage(保存文件到外置存储)

Because the external storage may be unavailable—such as when the user has mounted the storage to a PC or has removed the SD card that provides the external storage—you should always verify that the volume is available before accessing it. You can query the external storage state by calling  getExternalStorageState() . If the returned state is equal to  MEDIA_MOUNTED , then you can read and write your files. For example, the following methods are useful to determine the storage availability:
译:因为外置存储可能是不可用的:比如当用户挂载存储器到PC,或者移除了提供外置存储的SD卡时,你应该在访问它之前总是验证它是否可用通过调用  getExternalStorageState() 方法。如果返回的状态与 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;}
Although the external storage is modifiable by the user and other apps, there are two categories of files you might save here:(尽管外置存储可能被用户或者其他app改变,但是这里仍有两类文件你需要保存到这里:)
Public files Files that should be freely available to other apps and to the user. When the user uninstalls your app, these files should remain available to the user.(这些文件对用户和其他app都是可访问的,当用户卸载app的时候,这些文件任然存在)

For example, photos captured by your app or other downloaded files.(比如,我们的app捕捉到 图片或者其他下载的 文件)

Private files Files that rightfully belong to your app and should be deleted when the user uninstalls your app. Although these files are technically accessible by the user and other apps because they are on the external storage, they are files that realistically don't provide value to the user outside your app. When the user uninstalls your app, the system deletes all files in your app's external private directory.(文件仅仅属于你的app,并且当用户卸载app的时候应该被删除。尽管这些文件在技术上来说是可以被用户或者第三方app访问,因为他们在外置存储器上,这些文件只有在使用我们的app时才会提供它的真实值。当用户卸载app时,系统会删除在app的私有目录下的所有文件) For example, additional resources downloaded by your app or temporary media files.(比如,你的app下载的附件的资源以及临时的媒体文件。)
If you want to save public files on the external storage, use the  getExternalStoragePublicDirectory()  method to get a  File  representing the appropriate directory on the external storage. The method takes an argument specifying the type of file you want to save so that they can be logically organized with other public files, such as  DIRECTORY_MUSIC  or  DIRECTORY_PICTURES . For example:

译:如果你想在外置存储上保存公共的文件,使用  getExternalStoragePublicDirectory()  方法 得到一个 File 对象,它代表在外置存储上的适当目录。这个方法带有一个指定你想保存的文件的类型的参数,这样他们可以与其他公共的文件合乎逻辑的组织起来,诸如 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;}

If you want to save files that are private to your app, you can acquire the appropriate directory by callinggetExternalFilesDir() and passing it a name indicating the type of directory you'd like. 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.

For example, here's a method you can use to create a directory for an individual photo album:

译:如果你想保存对你的app来说是私有的文件,你可以通过调用   getExternalFilesDir() 方法来获取一个合适的目录,并且传递给它一个表明你想要的目录类型的名字。每一个通过这种方式创建的目录被添加到一个父目录,这个父目录封装了你的app 的所有外部存储文件,而且这个目录会在在用户卸载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;}

If none of the pre-defined sub-directory names suit your files, you can instead call getExternalFilesDir() and pass null. This returns the root directory for your app's private directory on the external storage.(译:如果没有预先定义适合你的文件的子目录的名字,你可以代替调用 getExternalFilesDir() 方法并且传一个null这时他会返回你的app在external storage下的private 的根目录。 )

Remember that getExternalFilesDir() creates a directory inside a directory that is deleted when the user uninstalls your app. If the files you're saving should remain available after the user uninstalls your app—such as when your app is a camera and the user will want to keep the photos—you should instead usegetExternalStoragePublicDirectory().(译:请记住,getExternalFilesDir() 方法创建的目录在app被卸载时会被系统删除。如果你保存的文件在用户卸载app之后应该继续存留下来,比如你的app是一个相机并且用户希望保存拍下的照片,你应该使用方法getExternalStoragePublicDirectory()。)

Regardless of whether you use getExternalStoragePublicDirectory() for files that are shared orgetExternalFilesDir() for files that are private to your app, it's important that you use directory names provided by API constants like DIRECTORY_PICTURES. These directory names ensure that the files are treated properly by the system. For instance, files saved in DIRECTORY_RINGTONES are categorized by the system media scanner as ringtones instead of music.

译:无论你是使用 getExternalStoragePublicDirectory()   方法为了保存共享的文件还是使用 getExternalFilesDir() 方法为了保存app 的私有文件,重要的是你要使用API 提供的像 DIRECTORY_PICTURES 这样的 目录名字。这些目录名字会确保那些文件被系统合适的处理。例如:保存在    DIRECTORY_RINGTONES   目录下的文件会被系统的媒体扫描组织起来作为铃声而不是音乐。

Query Free Space(查询可用空间)

If you know ahead of time how much data you're saving, you can find out whether sufficient space is available without causing an IOException by calling getFreeSpace() or getTotalSpace(). These methods provide the current available space and the total space in the storage volume, respectively. This information is also useful to avoid filling the storage volume above a certain threshold.

译:如果你能提前知道你存储的数据有多大,你可以通过调用 getFreeSpace() 或者 getTotalSpace()方法发现是否有足够的空间来保存文件,从而避免造成IO异常。那些方法可以分别得到存储卷中当前可用的空间以及总空间。这些信息在避免有确定的阈值时写数据到存储卷非常有用。

However, the system does not guarantee that you can write as many bytes as are indicated by getFreeSpace(). If the number returned is a few MB more than the size of the data you want to save, or if the file system is less than 90% full, then it's probably safe to proceed. Otherwise, you probably shouldn't write to storage.

译:然而,系统不会担保你可以写与方法 getFreeSpace() 指示的那样多的字节数。如果返回的数字只有几兆而不是你想要保存数据的大小,或者如果文件系统使用率少于90%,这时获取可以安全的执行保存操作,否则你可能不应该执行写操作。

Note:  You aren't required to check the amount of available space before you save your file. You can instead try writing the file right away, then catch an  IOException  if one occurs. You may need to do this if you don't know exactly how much space you need. For example, if you change the file's encoding before you save it by converting a PNG image to JPEG, you won't know the file's size beforehand.

译:注意:在保存你的文件时并没有强制要求去检查当前可用空间的总量。你可以尝试写文件,然后通过捕获 IOException 如果发生了IO异常。在你不能精确知道你需要多大的 空间时你可能这样做。例如:在你保存文件之前如果你把文件的编码从PNG格式的图片变为JPEG格式的图片,你处理之前无法知道文件的大小。

Delete a File(删除一个文件)

You should always delete files that you no longer need. The most straightforward way to delete a file is to have the opened file reference call delete() on itself.

译:你应该删除一个文件当你不再需要它时。最简单的删除一个文件的方式是得到所打开文件的引用并且用它调用  delete() 。

myFile.delete();
If the file is saved on internal storage, you can also ask the  Context  to locate and delete a file by calling deleteFile() :

译:如果文件保存在内置存储中,你也可以通过Context去定位并删除一个文件通过调用 deleteFile():

myContext.deleteFile(fileName);

Note: When the user uninstalls your app, the Android system deletes the following:(译:当用户卸载你的app时,Android系统会删除以下文件:)

  • All files you saved on internal storage(译:你保存在内存存储中的所有文件)
  • All files you saved on external storage using getExternalFilesDir().(译:通过使用 getExternalFilesDir()方法保存在外置存储中的多有文件

However, you should manually delete all cached files created with getCacheDir() on a regular basis and also regularly delete other files you no longer need.(译:然而,你应该手动删除所有通过 getCacheDir() 方法得到目录下的缓存文件以及那些不再需要的文件。)


翻译自该原文:http://developer.android.com/training/basics/data-storage/files.html#InternalVsExternalStorage









更多相关文章

  1. 一款常用的 Squid 日志分析工具
  2. GitHub 标星 8K+!一款开源替代 ls 的工具你值得拥有!
  3. RHEL 6 下 DHCP+TFTP+FTP+PXE+Kickstart 实现无人值守安装
  4. Linux 环境下实战 Rsync 备份工具及配置 rsync+inotify 实时同步
  5. [置顶] 关于Socket的简单解析
  6. Android(安卓)实现对话框圆角功能
  7. Android常见abd指令集
  8. Android炫酷之动画简记
  9. Android开发 如何最优的在Activity里释放资源

随机推荐

  1. android studio一键生成快速开发实现语言
  2. Android(安卓)Studio 从2.3.1升级到3.4.1
  3. Android(安卓)如何快速定位当前页面是哪
  4. Android仿淘宝头条滚动广告条
  5. Android8.0、Android9.0 通知notificatio
  6. android 开机铃音和开机图片以及系统自带
  7. android 对dp单位的理解
  8. android之AsyncQueryHandler详解
  9. Android(安卓)仿直播特效点赞飘爱心
  10. Activity之launchMode(运行模式)