Android数据存储方式之——文件存储

说明

    博客中会慢慢添加Android系列教程,均是参考至官网的教程,能保证使用方式都不会过时,此处也建议学习Android的读者直接参考官网的文档,毕竟技术更新太快,买的书不能保证内容是最新的。当然看官方文档需要一定的英文基础,如果英文不过关也没关系,边看边学(自己拿去翻译吧),一举两得。学习的过程一定是枯燥的,望而止步的,也别指望能把一门技术学得多好。

    本篇将的是将数据存储到External Storage(比如sdcard)上,数据库和xml方式的数据存储确实方便,但并不能完成一个应用的所有数据存放。

    下面会引用部分官方文档的说明(毕竟鄙人的英文水平有限,放出原文更佳)。

概述

    Android 使用与其他平台上基于磁盘的文件系统类似的文件系统。Android 文件系统通过 File API 读取和写入文件。 File 对象适合按照从开始到结束的顺序不跳过地读取或写入大量数据。 例如,它适合于图像文件或通过网络交换的任何内容。 (本课程假定读者熟悉Linux 文件系统的基础知识和 java.io 中的标准文件输入/输出 API

内部或外部存储

    所有 Android 设备都有两个文件存储区域:“内部”和“外部”存储。这些名称在 Android 早期产生,当时大多数设备都提供内置的非易失性内存(内部存储),以及移动存储介质,比如微型 SD 卡(外部存储)。一些设备将永久性存储空间划分为“内部”和“外部”分区,即便没有移动存储介质,也始终有两个存储空间,并且无论外部存储设备是否可移动,API 的行为均一致。

    内部存储

  •     它始终可用。
  •     默认情况下只有当前应用可以访问此处保存的文件。
  •     当用户卸载应用时,系统会从内部存储中删除应用的所有文件。

    当希望确保用户或其他应用均无法访问文件时,内部存储是最佳选择。

    外部存储

  •     它并非始终可用,因为用户可采用 USB 存储的形式装载外部存储,并在某些情况下会从设备中将其删除。
  •     它是全局可读的,因此此处保存的文件可能不受控制地被读取。
  •     当用户卸载应用时,只有在通过 getExternalFilesDir() 将应用的文件保存在目录中时,系统才会从此处删除应用的文件。

    对于无需访问限制以及希望与其他应用共享或允许用户使用电脑访问的文件,外部存储是最佳位置。

    提示:尽管应用默认安装在内部存储中,但可在AndroidManifest.xml中指定 android:installLocation 属性,这样应用便可安装在在外部存储中。 当 APK 非常大且它们的外部存储空间大于内部存储时,用户更青睐这个选择。 如需了解详细信息,请参阅应用安装位置

获取外部存储的权限

    要向外部存储写入信息,必须在AndroidManifest.xml文件中请求 WRITE_EXTERNAL_STORAGE 权限:

<manifest ...>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    ...
</manifest>

    WRITE_EXTERNAL_STORAGE权限隐式的包含了READ_EXTERNAL_STORAGE权限,所以如果需要同时得到读和写的权限,只需要声明WRITE_EXTERNAL_STORAGE即可。

    无需任何权限,即可在内部存储中保存文件。 应用始终具有在其内部存储目录中进行读写的权限。

将文件保存在内部存储中

    getFilesDir()

    Returns the absolute path to the directory on the filesystem where files created with openFileOutput(String, int) are stored. The returned path may change over time if the calling app is moved to an adopted storage device, so only relative paths should be persisted. No additional permissions are required for the calling app to read or write files under the returned path.

    返回表示应用的内部目录的File。

    getCacheDir()

    Returns the absolute path to the application specific cache directory on the filesystem. These files will be ones that get deleted first when the device runs low on storage. There is no guarantee when these files will be deleted.

    Note: you should not rely on the system deleting these files for you; you should always have a reasonable maximum, such as 1 MB, for the amount of space you consume with cache files, and prune those files when exceeding that space.

    The returned path may change over time if the calling app is moved to an adopted storage device, so only relative paths should be persisted. Apps require no extra permissions to read or write to the returned path, since this path lives in their private storage.

    返回表示应用临时缓存文件的内部目录的 File 。 务必删除所有不再需要的文件并对在指定时间使用的内存量实现合理大小限制,比如,1MB。 如果在系统即将耗尽存储,它会在不进行警告的情况下删除缓存文件。

    要在这些目录之一中新建文件,可以使用 File() 构造函数,传递指定内部存储目录的上述方法之一所提供的 File 。例如:

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

    注意: 应用的内部存储设备目录由应用在Android 文件系统特定位置中的软件包名称指定。在技术上,如果将文件模式设置为可读,另一个应用可以读取内部文件。 但是,另一个应用也需要知道应用的软件包名称和文件名。 其他应用无法浏览内部目录并且没有读写权限,除非明确将文件设置为可读或可写。 只要为内部存储上的文件使用 MODE_PRIVATE, 其他应用便从不会访问它们。

将文件保存在外部存储中

    由于外部存储可能不可用,比如,当用户已将存储装载到电脑或已移除提供外部存储的 SD 卡时,因此,在访问它之前,应始终确认其容量。 可以通过调用 getExternalStorageState() 查询外部存储状态。 如果返回的状态为 MEDIA_MOUNTED,那么变可以对文件进行读写。 例如,以下方法对于确定存储可用性非常有用:

    public static boolean isExternalStorageWritable(){
        // MEDIA_MOUNTED:
        // state if the media is present and mounted at its mount point with read/write access.
        return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
    }
    /**
     * 检查存储是否可以读
     * @return true or false
     */
    public static boolean isExternalStorageReadable(){
        // MEDIA_MOUNTED_READ_ONLY:
        // Storage state if the media is present and mounted at its mount point with read-only access.
        String state = Environment.getExternalStorageState();
        return Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)|| Environment.MEDIA_MOUNTED.equals(state);
    }

     尽管外部存储可被用户和其他应用进行修改,但可在此处保存两类文件:

    1、公共文件:应供其他应用和用户自由使用的文件。 当用户卸载应用时,用户应仍可以使用这些文件。 例如,应用拍摄的照片或其他已下载的文件。

    2、私有文件:本属于应用且应在用户卸载应用时删除的文件。尽管这些文件在技术上可被用户和其他应用访问(因为它们在外部存储上),它们是实际上不向应用之外的用户提供值的文件。当用户卸载应用时,系统会删除应用外部专用目录中的所有文件。

    如果要使用外部存储上的公共文件,请使用 getExternalStoragePublicDirectory() 方法获取表示外部存储上相应目录的 File 。该方法使用指定想要保存以便它们可以与其他公共文件在逻辑上组织在一起的文件类型的参数,比如 DIRECTORY_MUSIC 或 DIRECTORY_PICTURES。 例如:

    /**
     * 在公共目录PICTURES下创建对应app的目录
     * @param albumName 要创建的目录
     * @return 这个目录
     */
    public static File getAlbumStorageDir(String albumName){
        File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),albumName);
        if(!file.mkdirs()){
            Log.e(LOG_TAG,"Directory not created");
        }
        return file;
    }

    如果要保存应用专用文件,可以通过调用 getExternalFilesDir() 获取相应的目录并向其传递指示想要的目录类型的名称。 通过这种方法创建的各个目录将添加至封装应用的所有外部存储文件的父目录,当用户卸载应用时,系统会删除这些文件。 例如,可以使用以下方法来创建个人相册的目录:

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。这将返回外部存储上应用的专用目录 的根目录。

    切记,getExternalFilesDir() 在用户卸载的应用时删除的目录内创建目录。如果正保存的文件应在用户卸载应用后仍然可用—比如,当应用是照相机并且用户要保留照片时—应改用 getExternalStoragePublicDirectory()。

    无论对于共享的文件使用 getExternalStoragePublicDirectory() 还是对应用专用文件使用 getExternalFilesDir() ,使用诸如 DIRECTORY_PICTURES 的 API 常数提供的目录名称非常重要。 这些目录名称可确保系统正确处理文件。 例如,保存在 DIRECTORY_RINGTONES 中的文件由系统介质扫描程序归类为铃声,而不是音乐。

查询可用空间

    如果事先知道将保存的数据量,可以查出是否有足够的可用空间,而无需调用 getFreeSpace() 或 getTotalSpace() 引起 IOException 。 这些方法分别提供目前的可用空间和存储卷中的总空间。 此信息也可用来避免填充存储卷以致超出特定阈值。 但是,系统并不保证可以写入与 getFreeSpace() 指示的一样多的字节。如果返回的数字比要保存的数据大小大出几 MB,或如果文件系统所占空间不到 90%,则可安全继续操作。否则,可能不应写入存储。

    注意:保存文件之前,无需检查可用空间量。 可以尝试立刻写入文件,然后在 IOException 出现时将其捕获。 如果不知道所需的确切空间量,可能需要这样做。 例如,如果在保存文件之前通过将 PNG 图像转换成JPEG 更改了文件的编码,事先将不知道文件的大小。

删除文件

    应始终删除不再需要的文件。删除文件最直接的方法是让打开的文件参考自行调用 delete():

myFile.delete();

    如果文件保存在内部存储中,还可以请求 Context 通过调用 deleteFile() 来定位和删除文件:

myContext.deleteFile(fileName);

    注意:当用户卸载应用时,Android 系统会删除以下各项:

  •     保存在内部存储中的所有文件
  •     使用 getExternalFilesDir() 保存在外部存储中的所有文件。

    但是,应手动删除使用 getCacheDir() 定期创建的所有缓存文件并且定期删除不再需要的其他文件。

    后期会不上Demo

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值