Android 保存到文件

保存到文件

存储在内部还是外部

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

Internal storage:
  • 总是可用的
  • 这里的文件默认是只能被你的app所访问的
  • 当用户卸载你的app的时候,系统会把internal里面的相关文件都清除干净

Internal是在你想确保不被用户与其他app所访问的最佳存储区域。

External storage:
  • 并不总是可用的,因为用户有时会通过USB存储模式挂载外部存储器,当取下挂载的这部分后,就无法对其进行访问了。
  • 是大家都可以访问的,因此你可能会失去保存在这里的文件的访问控制权。
  • 当用户卸载你的app时,系统仅仅会删除保存在用 getExternalFilesDir() 创建的目录下的文件。

External是在你不需要严格的访问权限并且你希望这些文件能够被其他app所共享或者是允许用户通过电脑访问时的最佳存储
区域。

获取External存储的权限

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

Caution: 目前,所有的apps都可以在不指定某个专门的权限下做读external storage的动作。但是,这在以后的版本中会有所改变。如果你的app只需要读的权限(不是写), 那么你将需要声明 READ_EXTERNAL_STORAGE 权限。为了确保你的app能持续地正常工作,你需要现在就声明读权限。

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

但是,如果你的程序有声明写的权限,那么就默认有了读的权限。

对于internal 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目录。(但是我没找到openFileOutput()这个方法,编译器不认识,也许是被淘汰了)

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;
}

尽管external storage对于用户与其他app是可修改的,但是你可能会保存下面两种类型的文件。

  • Public files :这些文件对于用户与其他app来说是public的。当用户卸载你的app时,这些文件应该保留。例如,那些被
    你的app拍摄的图片或者下载的文件。
  • Private files: 这些文件应该是被你的app所拥有的,它们应该在你的app被卸载时删除掉。尽管由于存储在external
    storage,这些文件从技术上而言可以被用户与其他app所访问,但实际上那些文件对于其他app是没有意义的。因此,
    当用户卸载你的app时,系统会删除你的app的private目录。例如,那些被你的app下载的缓存文件。

如果你想要保存文件为public形式的,请使用getExternalStoragePublicDirectory()方法来获取一个 File 对象来表示存储在external storage的目录。这个方法会需要你带有一个特定的参数来指定这些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;
}

如果你想要保存文件为私有的方式,你可以通过执行getExternalFilesDir() 来获取相应的目录,并且传递一个指示文件类型的参数。每一个以这种方式创建的目录都会被添加到包含所有你app的external storage文件的父目录下。这个父目录(包括目录下的文件)会在用户卸载你的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而不是音乐。

查询剩余空间

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

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

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

删除文件

myFile.delete();

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

myContext.deleteFile(fileName);

Note: 当用户卸载你的app时,android系统会删除以下文件:
所有保存到internal storage的文件。
所有使用getExternalFilesDir()方式保存在external storage的文件。
然而,通常来说,你应该手动删除所有通过 getCacheDir() 方式创建的缓存文件,以及那些不会再用到的文件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值