内容简介:所有Android设备都有两个文件存储区:“内部”和“外部”存储。这些名称来自Android的早期,大多数设备提供内置的非易失性存储器(内部存储),以及可移动存储介质,如由于外部存储可能是可移除的,因此这两个选项之间存在一些差异,如下所示。您的应用程序的内部存储目录由您的应用程序包名称指定在Android文件系统的特殊位置,可以使用以下API访问。
所有Android设备都有两个文件存储区:“内部”和“外部”存储。这些名称来自Android的早期,大多数设备提供内置的非易失性存储器(内部存储),以及可移动存储介质,如 micro
SD卡(外部存储)。现在,许多设备将永久存储空间划分为单独的“内部”和“外部”分区。因此,即使没有可移动存储介质,这两个存储空间也始终存在,无论外部存储是否可移动,API行为都是相同的。
由于外部存储可能是可移除的,因此这两个选项之间存在一些差异,如下所示。
内部存储器:
- 它始终可用。
- 内部存储器保存的文件只能由您的应用访问。
- 当用户卸载您的应用程序时,系统会从内部存储中删除所有应用程序的文件。
- 当您希望确保用户和其他应用程序都无法访问您的文件时,最好使用内部存储。
外部存储:
getExternalFilesDir()
将文件保存在内部存储上
您的应用程序的内部存储目录由您的应用程序包名称指定在Android文件系统的特殊位置,可以使用以下API访问。
注意
:与外部存储目录不同,您的应用程序不需要任何系统权限来读取和写入这些方法返回的内部目录。
写一个文件
将文件保存到内部存储时,可以通过调用以下两种方法获取相应的目录,进一步操作 File
:
getFilesDir() getCacheDir()
要在其中一个目录中创建新文件,可以使用File()构造函数,传递给 File
上述方法提供的指定内部存储目录的方法。
例如:
File file = new File(context.getFilesDir(), filename); 复制代码
或者,您可以调用 openFileOutput()
以获取 FileOutputStream
写入内部目录中的文件的内容。
例如,以下是如何将一些文本写入文件:
String filename = "myfile"; String fileContents = "Hello world!"; FileOutputStream outputStream; try { outputStream = openFileOutput(filename, Context.MODE_PRIVATE); outputStream.write(fileContents.getBytes()); outputStream.close(); } catch (Exception e) { e.printStackTrace(); } 复制代码
MODE_PRIVATE
将会创建文件(或替换具有相同名称的文件),并将其设为应用的私有文件。 其他可用模式包括: MODE_APPEND
、 MODE_WORLD_READABLE
和 MODE_WORLD_WRITEABLE
。
请注意,该openFileOutput()方法需要文件模式参数。传递 MODE_PRIVATE
将会创建文件(或替换具有相同名称的文件),并将其设为应用的私有文件。 其他可用模式包括: MODE_APPEND
、 MODE_WORLD_READABLE
和 MODE_WORLD_WRITEABLE
。
自 API 级别 17 以来,常量 MODE_WORLD_READABLE
和 MODE_WORLD_WRITEABLE
已被弃用。从 Android N(7.0,API24)
开始,使用这些常量将会导致引发 SecurityException。这意味着,面向 Android N 和更高版本的应用无法按名称共享私有文件,尝试共享“file://”URI 将会导致引发 FileUriExposedException
。 如果您的应用需要与其他应用共享私有文件,则可以将 FileProvider
与 FLAG_GRANT_READ_URI_PERMISSION
配合使用
在Android 6.0(API级别23)及更低级别上,如果您将文件模式设置为全局可读,则其他应用程序可以读取您的内部文件。但是,其他应用必须知道您的应用包名称和文件名。除非您明确将文件设置为可读或可写,否则其他应用程序无法浏览您的内部目录并且没有读取或写入权限 ·因此,只要您在内部存储上使用
MODE_PRIVATE 标记您的文件,其他应用就永远无法访问它们
。
写一个缓存文件
如果你需要缓存一些文件,你应该使用 createTempFile()
。
例如,以下方法从 URL
中提取文件名,并在应用程序的内部缓存目录中创建具有该名称的文件:
private 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; } 复制代码
使用 createTempFile()
创建的文件放置在应用程序专用的缓存目录中。您应该定期删除不再需要的文件。
注意
: 如果系统存储空间不足,可能会在没有警告的情况下删除缓存文件,因此请确保在读取之前检查缓存文件是否存在。
打开现有文件
要读取现有文件,请调用 openFileInput(name)
,传递文件名。
您可以通过调用获取所有应用程序文件名的数组 fileList()
。
注意
:如果您需要在应用程序中打包一个可在安装时访问的文件,请将该文件保存在项目的 res/raw/
目录中。您可以使用 openRawResource()
传递资源ID 打开这些文件。此方法返回可用于读取文件的方法。您无法写入原始文件。
打开一个目录
您可以使用以下方法在 内部文件
系统上打开目录:
-
getFilesDir()
:返回File表示文件系统上与您的应用唯一关联的目录。 -
getDir(name, mode)
:在应用程序的唯一文件系统目录中创建新目录(或打开现有目录)。此新目录显示在提供的目录中getFilesDir()
。 -
getCacheDir()
:返回File表示文件系统上与您的应用唯一关联的缓存目录。此目录适用于临时文件,应定期清理。如果磁盘空间不足,系统可能会删除那里的文件,因此请确保在读取之前检查缓存文件是否存在。
要在其中一个目录中创建新文件,可以使用 File()构造函数,传递File上述方法之一提供的指定内部存储目录的对象。
例如:
File directory = context.getFilesDir(); File file = new File(directory, filename); 复制代码
将文件保存在外部存储上
使用外部存储非常适合您要与 其他应用共享
或 允许用户使用计算机访问的文件
。
在 请求存储权限
并 验证存储可用后
,您可以保存两种不同类型的文件:
公共文件 私人文件
注意
: 如果用户卸下SD卡或将设备连接到计算机,外部存储可能会变得不可用
。并且用户和具有 READ_EXTERNAL_STORAGE
权限的其他应用程序仍然可以看到这些文件。因此,如果您的应用程序的功能取决于这些文件,或者您需要完全限制访问,则应将文件写入内部存储。
请求外部存储权限
要写入公共外部存储,您必须在清单文件中请求 WRITE_EXTERNAL_STORAGE
权限:
<uses-permission android:name = “android.permission.WRITE_EXTERNAL_STORAGE” /> 复制代码
如果您的应用使用该 WRITE_EXTERNAL_STORAGE
权限,则它也隐式拥有读取外部存储的权限。
如果您的应用只需要读取外部存储(但不能写入)
,那么您需要声明 READ_EXTERNAL_STORAGE
权限:
<uses-permission android:name = “android.permission.READ_EXTERNAL_STORAGE” /> 复制代码
从Android 4.4(API级别19)开始,在应用程序的私有外部存储目录中读取或写入文件 - 使用 getExternalFilesDir()
访问, 不需要 READ_EXTERNAL_STORAGE
或 WRITE_EXTERNAL_STORAGE
权限。因此,如果您的应用支持Android 4.3(API级别18)及更低版本,并且您只想访问专用外部存储目录,则应通过添加maxSdkVersion 属性声明仅在较低版本的Android上请求权限 :
<uses-permission android:name = “android.permission.WRITE_EXTERNAL_STORAGE” android:maxSdkVersion = “18” /> 复制代码
验证外部存储是否可用
由于外部存储可能不可用 - 例如当用户将存储装置安装到PC或已移除提供外部存储的SD卡时 - 您应始终在访问之前验证该卷是否可用。您可以通过调用来查询外部存储状态 getExternalStorageState()
。如果返回状态为 MEDIA_MOUNTED
,则可以读取和写入文件。如果是 MEDIA_MOUNTED_READ_ONLY
,则只能读取文件。
例如,以下方法可用于确定存储可用性:
/* 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; } 复制代码
保存到外部公共目录
如果要将公共文件保存在外部存储上,请使用该 getExternalStoragePublicDirectory()
方法获取File表示外部存储上的相应目录。该方法接受一个参数,指定要保存的文件类型,以便可以使用其他公共文件(如DIRECTORY_MUSIC或) 对其进行逻辑组织DIRECTORY_PICTURES。例如:
public File getPublicAlbumStorageDir(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; } 复制代码
如果要从 Media Scanner
中隐藏文件,请在外部文件目录中包含一个名为 .nomedia
空文件(请注意文件名 中的点前缀)。这可以防止媒体扫描程序读取您的媒体文件,并通过 MediaStore
内容提供商将其提供给其他应用程序。
保存到外部私有目录
如果要将文件保存在应用程序专用且外部提供程序无法访问的外部存储上 MediaStore
,您可以通过调用 getExternalFilesDir()
并向其传递一个名称来获取一个目录,该目录仅由您的应用程序使用, 该名称指示您希望的目录类型。以这种方式创建的每个目录都会添加到父目录中,该目录封装了应用程序的所有外部存储文件,系统会在用户卸载应用程序时将其删除。
public File getPrivateAlbumStorageDir(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()
创建一个在用户卸载应用程序时删除的目录。如果您保存的文件在用户卸载应用程序后仍然可用 - 例如当您的应用程序捕获照片并且用户应保留这些照片时 - 您应该将文件保存到公共目录。
在多个存储位置之间选择
有时,分配内部存储器分区以用作外部存储器的设备也提供SD卡插槽。这意味着该设备有两个不同的外部存储目录,因此您需要选择在将“私有”文件写入外部存储时使用哪个目录。
从Android 4.4(API级别19)开始,您可以通过调用访问这两个位置 getExternalFilesDirs()
,该位置 返回一个包含每个存储位置条目的 File
数组。数组中的第一个条目被视为主要外部存储,您应该使用该位置,除非它已满或不可用。
如果您的应用支持Android 4.3及更低版本,则应使用支持库的静态方法 ContextCompat.getExternalFilesDirs()
。这总是返回一个File数组,但如果设备运行的是Android 4.3及更低版本,那么它只包含一个主外部存储条目(如果有第二个存储位置,则无法在Android 4.3及更低版本上访问它)。
删除文件
您应该始终删除您的应用不再需要的文件。删除文件最直接的方法是调用 File
对象 delete()
方法。
myFile.delete(); 复制代码
如果文件保存在内部存储器上,您还可以通过调用 Context
的 deleteFile()
来查找和删除文件:
myContext.deleteFile(fileName ); 复制代码
注意:当用户卸载您的应用时,Android系统会删除以下内容:
getExternalFilesDir()
Android 目录总结
($rootDir) +- /data -> Environment.getDataDirectory() | | | | ($appDataDir) | +- data/com.srain.cube.sample | | | | ($filesDir) | +- files -> Context.getFilesDir() / Context.getFileStreamPath("") | | | | | +- file1 -> Context.getFileStreamPath("file1") | | ($cacheDir) | +- cache -> Context.getCacheDir() | | | +- app_$name ->(Context.getDir(String name, int mode) | | ($rootDir) +- /storage/sdcard0 -> Environment.getExternalStorageDirectory() | / Environment.getExternalStoragePublicDirectory("") | +- dir1 -> Environment.getExternalStoragePublicDirectory("dir1") | | ($appDataDir) +- Andorid/data/com.srain.cube.sample | | ($filesDir) +- files -> Context.getExternalFilesDir("") | | | +- file1 -> Context.getExternalFilesDir("file1") | +- Music -> Context.getExternalFilesDir(Environment.Music); | +- Picture -> ... Environment.Picture | +- ... | | ($cacheDir) +- cache -> Context.getExternalCacheDir() | +- ??? 复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- python将每个单词按空格分开并保存到文件中
- 【代码+数据】Python采集《毛选5》并保存为xhtml文件
- python将文本分每两行一组并保存到文件
- Spring MVC将上传的MultipartFile保存到特定文件夹
- Go后台对图片base64解码,并保存至文件服务器。
- js基础--将内存中的数据保存为文件下载到本地
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。