Android数据存储

目录结构:

/
 +- data  (用户数据目录,Environment.getDataDirectory())
 |    +- app
 |    +- data
 |         +- 包名 (私有内部存储)
 |             +- shared_prefs
 |             +- databases
 |             +- files(context.getFilesDir())
 |                  +- 自定义目录名(context.getFileStreamPath())
 |             +- cache(context.getCacheDir())
 |             +- app_自定义名称(context.getDir(自定义名称))
 +- mnt或storage或sdcard  (外部存储,Environment.getExternalStorageDirectory())
            +- 九大公共目录(Environment.getExternalStoragePublicDirectory(指定字符串))
            +- 自定义目录(Environment.getExternalStoragePublicDirectory(自定义字符串))
            +- Android
                  +- data
                       +- 包名(私有外存目录)
                           +- files(context.getExternalFilesDir(null))
                                +- 九大私有目录(context.getExternalFilesDir(指定字符串))
                                +- 自定义私有目录(context.getExternalFilesDir(自定义字符串))
                           +- cache(context.getExternalCacheDir())

getExternalFilesDir():私有外部存储,4.4开始访问这类应用私有目录不用读写权限,所以只要在API 19以前请求权限就好:

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

对于这个目录有几个需要注意的地方,首先因为是应用私有存储,所以应用删除的时候这个目录也会被删除掉,同时MediaScanner不会扫描到这个目录中的内容,也就无法从MediaStore这个Content Provider中获取了。第二个注意点是其他应用如果具有READ_EXTERNAL_STORAGE权限,就可以访问外部存储的所有文件,也就包括了这个目录。

某些手机把内部存储划出一部分作为外部存储来用,同时又提供SD卡插槽,这种情况下4.3以下,getExternalFilesDir()只会返回伪外部存储,无法返回SD卡存储。4.4开始可以调用getExternalFilesDirs()返回外部存储数组供我们访问。

SharedPreference

getSharedPreference() 获取指定的sp文件
getPreference() 使用Activity名称作为sp文件名

内部存储

openFileOutput 返回FileOutputStream
openFileInput 返回FileInputStream
可以通过openRawResource()方法获取InputStream读取res/raw/的文件

内存目录
getCacheDir() 获取app的内部缓存目录,最好要给该目录设置一个合理的大小,如果系统存储空间不足,会自动删除缓存目录里的文件
getFilesDir() 获取app的内部存储目录

可以通过

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

获取app私有的文件对象,或者使用openFileOutput()、openFileInput()方法获取输出流或者输入流,例如

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

可以这样创建一个缓存文件

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

createTempFile方法三个参数分别是文件名的前缀、扩展名、还有保存目录。生成的文件名的组成是前缀加上系统自动生成的字符串加上扩展名。
如果扩展名为null,则使用默认的.tmp扩展名。保存目录如果没有指明,则使用系统默认缓存目录,UNIX系统中是/tmp或者/var/tmp,Windows系统是C:\WINNT\TEMP。
createTempFile要实现完整的缓存机制,还需要配合调用deleteOnExit()方法,这样在虚拟机退出的时候会把缓存文件自动删除掉。

getDir()新建或打开目录
deleteFile()删除内部存储文件
fileList()返回当前应用保存的文件

外部存储

所有的Android设备都有两个存储区域:内部存储和外部存储。如果没有SD卡的话,就把内部存储划出一部分来当做外部存储。

检测是否存在外部存储:

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

外部存储的目录可分为私有跟公有两种,私有跟公有的区别在于,私有目录下的文件在APP卸载时会一起删掉,同时无法被MediaScanner扫描到。

注意对于外部存储,不管是私有还是公有目录,对于有权限的其他应用来说,都是可以读取的。

如果想要保存公共的外部文件,可以调用 getExternalStoragePublicDirectory()方法,该方法接收一个文件类型参数,比如 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在外部存储的私有根目录下,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在外部存储的私有根目录。

注意getExternalFilesDir()返回的目录在app卸载时会被清理掉。

不管是使用 getExternalStoragePublicDirectory(),或者getExternalFilesDir()方法获取存储目录,使用系统定义的目录常量是很重要的,比如说DIRECTORY_PICTURES,这样系统媒体扫描器可以把该目录下的文件分类到正确的文件种类下。

查询剩余空间

可以使用getFreeSpace()或者getTotalSpace()方法获取剩余存储空间,这样可以避免空间不足的IOException。当然前提是要知道要写入文件的大小,如果不知道或者不想要查询后再写,可以直接写入,然后捕获IOException。getFreeSpace()返回的空间有点虚高,实际可写入可能没那么多。

删除文件

myFile.delete();

如果文件是保存在内部存储的,也可以通过Context对象去调用deleteFile()方法。

myContext.deleteFile(fileName);

用户卸载app时,系统删除以下文件:
1. 保存在内部存储的所有文件
2. 通过getExternalFilesDir()方法获取到的外部存储目录下的文件。
不过我们应该手动删除 getCacheDir() 下的文件,并及时删除不用的文件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值