Android 内部存储与外部存储

需求背景:

app应用开发都要用到文件存储,常见的如apk的更新安装,图片文件的外部缓存,保存和提取文件内容,随着不同手机厂商特别是华为手机对手机存储目录设置更是不拘一格,甚至不同Android系统版本,特别是7.0Android 系统对文件的访问更需要添加额外代码,在这样的情况下,小编搜集一些资料做一个专题总结。
前言:
保存文件: 用File对象按照从开始到结束的顺序不跳过地读取或写入大量数据。它适合于图片文件或通过网络交换的任何内容
内部存储和外部存储
所有Android设备都有两个文件存储区域:”内部”和”外部”存储,大多数设备都提供内置的非易失性内存(内部存储),以及移动存储介质,比如微型SD卡(外部存储)。一些设备将永久性存储空间分为”内部”和”外部”分区,即便没有移动存储介质,也始终有两个存储空间,并且无论外部存储设置是否可移动,API的行为一致,以下介绍各个存储空间的实际信息
内部存储:

  • 它始终可用
  • 只有您的应用可以访问此处保存的文件
  • 当用户卸载您的应用时,系统会从内部存储中移除您的应用的所有文件
    备注:当您希望确保用户或其他应用均无法访问您的文件时,内部存储是最佳选择
    外部存储:

  • 它并非始终可用,因为用户可采用USB存储设备的形式装载外部存储,并在某些情况下会从设备中移除。但是如果是手机自身将永久性存储空间分为”内部”和”外部”分区,外部存储不受usb挂载的影响

  • 它是全局可读可写的,因此此处保存的文件会在自己的控制之外,因为他们被用户打开并操作,所以在开发过程中注意这个操作的考虑
  • 当用户卸载您的应用时,只有在您通过getExternalFileDir(有SD卡的情况:应用的存储目录)将您的应用的文件保存在目录中时,系统才会从此处移除您的应用的文件。
    备注: 对于无需访问限制以及您希望与其他应用共享或允许用户使用计算机访问的文件,外部存储是最佳位置。
    重要说明:尽管应用默认安装在内部存储中,但您可在您的清单文件中指定android:installLocation属性,这样您的应用便可安装在外部存储中。当APK非常大且它们的外部存储空间大于“内部存储时,用户更青睐这个选择。详细可阅读开发者官网”应用安装位置”文章。(据我了解,现在的手机系统已不做应用搬家的支持了,所以这个属性没有可用价值)
    获取外部存储权限
    要向外部存储写入信息,必须请求” WRITE_EXTERNAL_STORAGE 权限”
<manifest ...>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    ...
</manifest>

注意:目前所有应用都可以读取外部存储,而无需特别的权限。但这在将来版本中会进行更改。如果应用需要读取外部存储(但不向其写入信息),那么您将需要声明 READ_EXTERNAL_STORAGE权限。

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

但是,如果应用使用 WRITE_EXTERNAL_STORAGE 权限,那么它也隐含读取外部存储的权限。您也无需任何权限,即可在内部存储中保存文件,您的应用始终具有在其内部存储目录中进行读写的权限。

将文件保存在内部存储中
在内部存储中保存文件时,您可以通过调用以下两种方法之一获取作为File的相应目录:
getFilesDir(): 应用的内部存储目录
getCacheDir(): 应用的内部缓存目录
如:

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

写入到文件: 可以调用openFilleOutput()获取到写入内部目录中的文件的FileOutputStream,例如下面显示向文件写入文本:

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

缓存某些文件: 使用createTempFile(),缓存某些文件,例如以下方法从URL提取文件名并在您的应用的内部缓存目录中以该名称创建文件:

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)
   {}
   return file;
}

备注: 您的应用的内部存储设备目录由您的应用在Android文件系统特定位置中的软件包名称指定。从技术上讲,如果您将文件模式设置为可读,那么另一个应用也可以读取您的内部文件。当然,此应用也需要知道您的应用的软件包名称和文件名。如果将内部存储文件使用MODE_PRIVATE,其它应用便从不会访问它们。
将文件保存在外部存储中
说明: 由于外部存储可能不可用,比如,当用户已将存储装载到电脑或已移除提供外部存储的SD卡时,因此,在访问它之前,应始终确认其容量。可以通过调用getExternalStorageState()查询外部存储状态。如果返回的状态为MEDIA_MOUNTED,那么您可以对您的文件进行读写。以下方法对于确定存储可用性非常有用:

//检查外部存储是否可用
public boolean isExternalStorageWritable()
{
    String state=Environment.getExternalStorageState();
    if(Environment.MEDIA_MOUNTED.equals(state))
    {
        return true;
    }
    return false;
}
//检查外部存储是否至少是可读的
public boolean isExternalStorageReadable()
{
    String state=Environment.getExternalStorageState();
    if(Environment.MEDIA_MOUNTED.getExternalStorageState()||Environment.MEDIA_MOUNTED_READ_ONLY.equals(state))
    {
       return true;
    }
    return false;
}

拓展: 尽管外部存储可被用户和其他应用进行修改,但您可在此处保存两类文件:
公共文件: 应供其他应用和用户自由使用的文件。当用户卸载您的应用时,用户仍可以使用这些文件。例如,您的应用拍摄的照片或其它已下载的文件。
私有文件: 属于您的应用且在用户卸载您的应用时应予删除的文件。
如果您要将公共文件保存在外部存储设备上,请使用getExternalStoragepublicDirecotry()方法获取表示外部存储设备上相应目录的File*。该方法的使用需要指定文件类型参数,比如DIRECTORY_MUSIC或DIRECTORY_PICTURES***。

public File getAlbumStorageDir(String albumName)
{
    //得到用户公有的图片存储目录
    File file=new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),ablubmName);
    if(!file.mkdirs())
    {
       Log.e("file_created","directory not created")
    }
    return file;
}

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

{
   File file=new File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES),albumName);
   if(!file.mkdirs())
   {
      Log.e("albumName","directory not created");
   }
   return file;
}

说明: 如果没有适合您文件的预定义子目录名称,可以调用getExternalFilesDir()的时候传递null.这将返回外部存储上您的应用的专用目录的根目录。如果要让应用卸载后保存在这个目录的文件仍然可用,此时应该改用getExternalStoragePublicDirectory()。
外部存储总结:无论您对于共享的文件使用getExternalStoragePublicDirectory()还是应用的专用文件getExternalFilesDir(),使用诸如DIRECTORY_PICTURES的API常数提供的目录名称非常重要。这些目录名称可确保系统正确处理文件。例如保存在DIRECTORY_RINGTONGS中的文件由系统媒体扫描程序归类为铃声,这样方便用户的文件管理和查看
查询可用空间

 getFreeSpace()方法提供目前的可用空间,getTotalSpace()方法获取存储卷中的空余空间。
 小窍门: 保存文件之前,可无需检查可用空间量。可以尝试立刻写入文件,然后在IOException出现时将其捕获,如果不知道所需的确切空间量,可以这样做。

删除文件
开发者应始终删除不再需要的文件,调用方法如

myfile.delete();

如果文件保存在内部存储中,还可以请求Context调用deleteFile来定位和删除文件
myContext.deleteFile(fileName);
注意: 当用户卸载您的应用时,Android系统会删除以下各项:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值