CSDN博客不再更新,新内容请移步掘金:https://juejin.im/user/5886d699128fe1006c455fb6,有问题也请直接发邮件至guoxiaoxingse@163.com...

【Android应用开发技术:文件读写】Android文件系统

作者:郭孝星
微博:郭孝星的新浪微博
邮箱:allenwells@163.com
博客:http://blog.csdn.net/allenwells
Github:https://github.com/AllenWells

【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时,系统仅仅会删除external根目录(getExternalFilesDir())下的相关文件。
  • External是在你不需要严格的访问权限并且你希望这些文件能够被其他app所共享或者是允许用户通过电脑访问时的最佳存储区域。

尽管App是默认被安装到Internal Storage的,我们还是可以通过在程序的AndroidManifest.xml文件中声明android:installLocation属性来指定程序也可以被安装到External Storage。当某个程序的安装文件很大且用户的internal Storage空间大于external Storage时,用户会倾向与将该程序安装到External Storage。

一 读写权限

对于Internal Storage,我们不需要声明任何权限,因为我们的程序默认就有读写程序目录下的文件的权限。而对于External Storage,我们需要获取相应的权限,获取External Storage写权限的方式如下所示:

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

现在的App都可以在不指定某个专门的权限下做读External Storage的动作。但是,这在以后的版本中会有所改变。如果我们的App只需要读的权限(不是写), 那么我们就需要声明READ_EXTERNAL_STORAGE权限。

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

二 文件读写

2.1 internal storage文件读写

当保存文件到internal storage时,你可以通过执行下面两个方法之一来获取合适的目录作为 FILE 的对象:

  • getFilesDir() : 返回一个File,代表了你的app的internal目录。
  • getCacheDir() : 返回一个File,代表了你的app的internal缓存目录。请确保这个目录下的文件在一旦不再需要的时候能够马上被删除,并对其大小进行合理限制,例如1MB 。如果系统的内部存储空间不够,会自行选择删除缓存文件。

获取到目录后,我们可以在该目录创建文件,如下所示:

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

我们也可以执行openFileOutput()来获取一个FileOutputStream用于写文件到Internal目录,如下所示:

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

我们的App在Internal Storage目录是以App的包名作为标识存放在Android文件系统的特定目录下,如下所示:

data/data/<package_name>

如果我们设置文件为可读的,而且App需要知道我们的包名与文件名,那么它们就可以读取我们的Internal文件。这种情况下我们可以使用MODE_PRIVATE来禁止其他App的读写。

2.1 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是可修改的,App存储到External Storage可能有两种类型,如下所示:

  • 公有文件:这些文件对与用户与其他App来说是公有的,当用户卸载我们的App时,这些文件应该保留。比如,那些被我们的App拍摄的图片或者下载的文件。
  • 私有文件:这些文件是被我们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()来获取相应的目录,并且传递一个指示文件类型的参数。每一个以这种方式创建的目录都会被添加到External Storage封装你的app目录下的参数文件夹下(如下则是albumName)。这下面的文件会在用户卸载你的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()或者getTotalSpace()来判断是否有足够的空间
来保存文件,从而避免发生IOException。那些方法提供了当前可用的空间还有存储系统的总容量。

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

写文件之前,并非一定有要去检查剩余容量。我们可以尝试先做写的动作,然后通过捕获IOException来分析容量是否不足。这种做法仅适合于事先不知道你想要写的文件的确切大小的情况。例如,如果在把PNG图片转换成JPEG之前,你并不知道最终生成的图片大小是多少。

三 文件删除

删除文件最直接的方法是直接执行文件的delete()方法,如下所示:

myFile.delete();

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

myContext.deleteFile(fileName);

当App被卸载时,Android系统会删除以下文件:

  • 所有保存到internal storage的文件。
  • 所有使用getExternalFilesDir()方式保存在external storage的文件。

除此之外,我们应该手动删除所有通过getCacheDir()方式创建的缓存文件,以及那些不会再用到的文件。

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

【Android应用开发技术:文件读写】Android文件系统

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭