欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

详解Android文件存储

程序员文章站 2024-02-13 23:39:04
摘要 其实安卓文件的操作和java在pc环境下的操作并无二致,之所以需要单独讲解是因为安卓系统提供了不同于pc的访问文件系统根路径的api,同时对一个应用的私有文件做了...

摘要

其实安卓文件的操作和java在pc环境下的操作并无二致,之所以需要单独讲解是因为安卓系统提供了不同于pc的访问文件系统根路径的api,同时对一个应用的私有文件做了统一的管理。根据我的经验,初学者在这部分感到很容易混淆内部存储和外部存储两个概念。

其实安卓文件的操作和java在pc环境下的操作并无二致,之所以需要单独讲解是因为安卓系统提供了不同于pc的访问文件系统根路径的api,同时对一个应用的私有文件做了统一的管理。根据我的经验,初学者在这部分感到很容易混淆内部存储和外部存储两个概念。

相对路径和绝对路径

在java中,关于相对路径和绝对路径是这样解释的,如果你很熟悉这部分以下灰色文字可以跳过:

绝对路径是指书写文件的完整路径,例如d:\java\hello.java,该路径中包含文件的完整路径d:\java以及文件的全名hello.java。使用该路径可以唯一的找到一个文件,不会产生歧义。但是使用绝对路径在表示文件时,受到的限制很大,且不能在不同的操作系统下运行,因为不同操作系统下绝对路径的表达形式存在不同。

相对路径是指书写文件的部分路径,例如\test\hello.java,该路径中只包含文件的部分路径\test和文件的全名hello.java,部分路径是指当前路径下的子路径,例如当前程序在d:\abc下运行,则该文件的完整路径就是d:\abc\test。使用这种形式,可以更加通用的代表文件的位置,使得文件路径产生一定的灵活性。

在eclipse项目中运行程序时,当前路径是项目的根目录,例如工作空间存储在d:\javaproject,当前项目名称是test,则当前路径是:d:\javaproject\test。在控制台下面运行程序时,当前路径是class文件所在的目录,如果class文件包含包名,则以该class文件最顶层的包名作为当前路径。

这是java在多数操作系统中这样操作,很显然是要我们尽可能的使用相对路径,但是在安卓中,其实多数情况下我们都是使用的绝对路径。为什么呢?注意上面说到相对路径是以当前项目所在路径为当前路径,但在安卓中我们是不可能在项目所在路径目录下做任何操作的,因为普通java中我们的项目创建于服务器(pc也算是服务器),运行于服务器,我们当然能在服务器操作自己的文件目录。但是安卓开发中,我们的项目一般是创建于自己工作的电脑,而运行于手机,既然apk已经运行于手机了,那项目就已经部署到手机上了,应该以apk在手机上的位置来确定相对路径,但我们好像们没有办法操作这个路径的,因为apk是在system目录下,就算可以操作,在这个目录下存取文件也是没有意义的,比如我写一个相册程序,图片肯定是放在外部存储中,而如果我要保存一个应用的一些设置数据,我是放在内部存储的data目录下,因此其实在安卓文件管理中,我们都是在操作绝对路径。

file类

操作一个文件(读写,创建文件或者目录)是通过file类来完成的,这个操作和java中完全一致。

internal storage内部存储空间

所谓的内部存储与外部存储,是指是否是手机内置。手机内置的存储空间,称为内部存储,它是手机一旦出厂就无法改变,它也是手机的硬件指标之一,通常来讲手 机内置存储空间越大意味着手机价格会越贵(很多地方把它称为手机内存,但我们做软件的知道,这并不准确,内存是指手机运行时存储程序,数据和指令的地方; 这里应该是手机内部存储的简称为内存,而并非严格意义上的内存)。

内部存储空间十分有限,因而显得可贵,所以我们要尽可能避免使用;另外,它也是系统本身和系统应用程序主要的数据存储所在地,一旦内部存储空间耗尽,手机 也就无法使用了。所以对于内部存储空间,我们要尽量避免使用。上面所谈到的shared preferences和下面要谈到的sqlite数据库也都是存储在内部存储空间上的。

android本身来讲是一个linux操作系统,所以它的内部存储空间,对于应用程序和用户来讲就是“/data/data"目录。它与其他的(外部的 存储)相比有着比较稳定,存储方便,操作简单,更加安全(因为可以控制访问权限)等优点。而它唯一的缺点就是它比较有限,比较可贵。

虽然,可以非常容易的知道程序本身的数据所在路径,所有的应用程序的数据路径都是“/data/data/app-package-name/”,所有的 程序用到的数据,比如libs库,sharedpreferences都是存放在这个路径下面。但我们在使用的时候最好不要,或是千万不要直接引用这个路 径。

使用内部存储主要有二个方式,一个是文件操作,一个是文件夹操作。无论哪种方式,context中都提供了相应的函数来支持,使用context不但操作 简单方便,最重要的是context会帮助我们管理这些文件,也可以方便帮助我们控制文件的访问权限。先来系统的说下context中关于文件和文件夹操 作的函数有哪些。

a. 创建一个文件,并打开成一个文件输出流,需要提供一个string,作为文件名

fileoutputstream output = context.openoutputfile(filename, context.mode_private); 
output.write(data);// use output to write whatever you like 
output.close();

b. 同样,想打开一个文件作为输入的话,也是只需要提供文件名

fileinputstream input = context.openinputfile(filename); 
input.read(); 
input.close();

c. 列出所有的已创建的文件

string[] files = context.filelist(); 
for (string file : files) { 
log.e(tag, "file is " + file); 
}

d. 删除文件,能创建就要能够删除,当然也会提供了删除文件的接口,它也非常简单,只需要提供文件名

if (context.deletefile(filename)) { 
log.e(tag, "delete file " + filename + " sucessfully“); 
} else { 
log.e(tag, "failed to delete file " + filename); 
}

e. 获取文件已创建文件的路径,它返回一个文件对象用于操作路径

file filedir = context.getfiledir(); 
log.e(tag, "filedir " + filedir.getabsolutepath();

f. 创建一个目录,需要传入目录名称,它返回 一个文件对象用到操作路径

file workdir = context.getdir(dirname, context.mode_private); 
log.e(tag, "workdir " + workdir.getabsolutepath();

g. 以file对象方式查看所创建文件,需要传入文件名,会返回文件对象

file store = context.getfilestreampath(filename); 
log.e(tag, "store " + store.length());

h. 获取cache路径,无需要传入参数,返回文件对象

file cachedir = context.getcachedir(); 
log.e(tag, "cachedir " + cachedir.getabsolutepath());

总结一下文件相关操作,可以得出以下三个特点

1. 文件操作只需要向函数提供文件名,所以程序自己只需要维护文件名即可;
2. 不用自己去创建文件对象和输入、输出流,提供文件名就可以返回file对象或输入输出流

3. 对于路径操作返回的都是文件对象。

如前所述,内部存储空间有限,可贵,安全,稳定,所以应该用来保存比较重要的数据,比如用户信息资料,口令秘码等不需要与其他应用程序共享的数据。也可以 用来创建临时文件,但一定要注意及时删除。另外,对于内部存储还有一个非常重要的特点,那就是在应用程序被卸载时,应用程序在内部存储空间的文件数据将全 部被删除。系统这样做的原因很简单,就是因为内部存储很有限,它必须保证它的可用性,因为一旦添满,系统将无法再正常工作。

external storage外部存储空间

再来谈谈手机外部存储空间,与内部存储空间相对,外部存储 空间是指手机出厂的时候不存在,用户在使用时候可以*添加的外部存储介质比如ts卡,sd卡等闪存储介质。这些闪存介质由最初的空间小价格贵,到现在的 大容量价格便宜,所以几乎每个支持外部存储的手机上面都有大容量(大于等于2g)的闪存卡。

android也是不例外,它完全支持外部存储介质。其实更确切的说,它是要依赖于外部存储卡的,因为对于android系统,如果没有外部存储卡,很多 的系统应用无法使用,比如多媒体相关的应用程序无法使用。虽然android很依赖,但是外部存储卡也有它自身的特点,它最大的优点就是存储空间大,基本 上你可无限制的使用,也不怎么担心去清除数据。就目前来看,很多程序都在使用外部存储卡,但很少有程序去主动清理数据,所以无论你的sd卡有多大,它的可 用空间却越来越少。与内部存储不同的是,当程序卸载时,它在外部存储所创建的文件数据是不会被清除的。所以清理外部存储空间的责任丢给了用户自己,每隔一 段时间就去查看下sd卡,发现无用数据立马删除。外部存储的缺点就是不是很稳定,对于android手机来讲可以说,很不稳定,本身闪存介质就容易出问 题,sd卡处于不能正常使用的状态十分多。

先来说说外部存储相关的使用方法和api

a check media availability检查介质的可用性.

如前所述,外部存储介质的稳定性十分的差,所以在使用之前一定要先检查它的可用性,如果可用再去用

final string state = environment.getexternalstoragestate(); 
if (state.equals(environment.media_mounted) || state.equals(environment.media_read_only)) {// sd card is ready to us 

b. get the directory获取外部存储卡的路径

事实上,外部存储卡的路径是“/mnt/sdcard",所以你直接这样写去访问也能访问的到。鉴于可读性和可移植性的考虑,建议这样写:

 file sdcarddir = environment.getexternalstoragedirectory();

c. for api 8 or greater, there are some other useful apis helping to manager files and directories.

如果你使用api 8(android 2.2)或者更高,那么sdk中又多了几个操作外部存储文件和路径的接口,文档中也建议开始者更加规范的使用sd卡。比如,创建相应的目录去存储相应的数 据,music,picture,video等。应用程序目录也变成了"/android/data/package-name/data"。具体的使用 可以参考文档,这里不重复。当然,就像编程规范一样,这里只是规范,你完全可以不遵守它,但出于可读性和可移植性,还是建议按照文档建议的去做。

下面总结一下使用时应该注意的一些和外部存储的特点

a. 外部存储卡不是随时想用就能够用的,所以一定要记得在使用之前检查它的可用性

b. 存储在外部存储卡上的数据是所有应用程序都可见,用户也可见(使用filemanager),所以安全性不是很好,虽然文档声称可以在外部存储卡上写程序 私有数据,但貌似没用,用filemanager仍然可以删除或编辑文件(market上面的filemanager功能都十分的强大,能让用户看到sd 卡中的所有文件,和操作能看到的文件)。

c. android手机支持把外部存储卡mount至pc做为u盘,当连接数据线时,这时sd卡变成了u盘连接到了另外的操作系统中。什么意思,就是在 android当中虽然有的文件属性(隐藏,私有等),到了pc上就不一定管用了,用户在pc上可以随意操作文件(这就是第二点中所提及的)。

d. 如果使用外部存储卡保存数据,一定要额外做好异常处理:外部存储卡不可用时把数据存入哪里;可用的时候再怎么同步数据(这是比较头疼的地方,可行的做法就 是当sd卡不可用时不准用户写数据,但这用户体验又不是很好,但如你所知,很多应用都这么干);你的数据被破坏了。当然常见的异常也要考虑,比如空间满 了,无法写入,磁盘坏道等。
我们还可以看一下常见的文件目录:

别忘了权限

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


log.i(tag, "getfilesdir = " + getfilesdir()); 
log.i(tag, "getexternalfilesdir = " + getexternalfilesdir("exter_test").getabsolutepath()); 
log.i(tag, "getdownloadcachedirectory = " + environment.getdownloadcachedirectory().getabsolutepath()); 
log.i(tag, "getdatadirectory = " + environment.getdatadirectory().getabsolutepath()); 
log.i(tag, "getexternalstoragedirectory = " + environment.getexternalstoragedirectory().getabsolutepath()); 
log.i(tag, "getexternalstoragepublicdirectory = " + environment.getexternalstoragepublicdirectory("pub_test"));

以上内容比较长,希望大家可以耐心阅读,本文所述全部都是精华,关于android文件存储相关知识,请点击本站了解更多。