关闭

Android数据存储之文件存储

标签: android内部存储外部存储
227人阅读 评论(0) 收藏 举报
分类:

内部存储和外部存储的概念

所有Android设备都有两个存储:”内部”和”外部”存储。早期Android设备的内部存储指的是内置的不可移除的内存,外部存储指的是sd card,也就是可移除存储。后来一些设备将内置存储划分为”内部”和”外部”分区,所以即便没有sd card这样的可移除存储,也始终有两个存储空间,并且无论外部存储是否可移除,API行为均一致。

内外部存储的实际路径

那么现在我们可以把存储分为三类:内部存储、不可移除的外部存储(内置内存划分的)、可移除外部存储(sd card)。
而外部存储保存的文件又分为两类:公有文件,私有文件。

内部存储目录:由 Context.getFilesDir() 获得,路径为 /data/data/com.example.capturephotodemo/files

内部存储缓存目录:由 Context.getCacheDir() 获得,路径为 /data/data/com.example.capturephotodemo/cache

外部存储私有文件存储目录:Context.getExternalFilesDir(String type)获得,传入 null 就是获取根目录 /storage/emulated/0/Android/data/com.example.capturephotodemo/files。如果传入 Environment.DIRECTORY_PICTURES,路径为 /storage/emulated/0/Android/data/com.example.capturephotodemo/files/Pictures

外部存储私公有文件目录(这里是由Environment获取,不是Context):Environment.getExternalStorageDirectory()获取是公有文件存储的根目录 /storage/emulated/0。Environment.getExternalStoragePublicDirectory(String type) 如果传入Environment.DIRECTORY_PICTURES,目录为/storage/emulated/0/Pictures

内外部存储区别

内部存储:始终可用,默认情况下只有当前应用可访问,用户卸载应用时,内部存储文件全部删除
外部存储:分为可移除和不可移除的,全局可读,不过当用户卸载应用时,只有私有文件(Context.getExternalFilesDir(String type),如下载的音频)会被删除,公有文件(Environment.getExternalStorageDirectory()或Environment.getExternalStoragePublicDirectory(String type),如拍照)不会被删除。

权限

写权限包含默认包含读的权限,不过一般为了版本兼容,必要时候还是加上读权限

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

保存文件到内部存储

先看下效果,点击Button后,会在ImageView中加载Internal Storage中的保存的图片,然后会把这个图片发送出去。
这里写图片描述

先创建图片

private void createInternalFile() {
    //在内部存储创建 images/ 目录
    File imagesDir = new File(getFilesDir(), shareDir);
    //在images/目录下创建文件
    internalFile = new File(imagesDir, "launcher.png");
    //打开文件的输出流
    FileOutputStream fos = null;
    try {
        fos = new FileOutputStream(internalFile);
        //获取bitmap对象
        Bitmap launcherIcon = BitmapFactory.decodeResource(getResources(), R.mipmap.star);
        //把bitmap对象压缩到输出流中
        boolean isCompressed = launcherIcon.compress(Bitmap.CompressFormat.PNG, 100, fos);
        if (!isCompressed) {
            Log.e("david", "Failed to compress");
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } finally {
        if (fos != null) {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

发送并加载

public void shareInternalFile(View view) {
    createInternalFile();

    //把文件以uri形式分享出去
    Uri uri = FileProvider.getUriForFile(this, AUTHORITY, internalFile);
    Intent shareIntent = new Intent(Intent.ACTION_SEND);
    shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
    shareIntent.setType("image/png");
    startActivity(Intent.createChooser(shareIntent,"Send Image"));

    //加载内部存储的文件,显示到ImageView中
    Bitmap bitmap = BitmapFactory.decodeFile(internalFile.getAbsolutePath());
    mImageView.setImageBitmap(bitmap);
}

既然内部存储只有本应用可以访问,那么接收图片的应用为何有权限访问这个图片。因为这里用了FileProvider,它赋予了Uri的临时权限

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.ckt.savingfile.provider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths"/>
</provider>

实际情况中,可能我要发送多张图片

ArrayList<Uri> imageUris = new ArrayList<Uri>();
imageUris.add(imageUri1); // Add your image URIs here
imageUris.add(imageUri2);

Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris);
shareIntent.setType("image/*");
startActivity(Intent.createChooser(shareIntent, "Share images to.."));

保存文件到外部存储

因为外部存储可能不存在,所以总是要先检查存在性。

/**
 * 检查外部存储是否挂载
 */
private boolean isExternalStorageAvailable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {
        return true;
    }
    return false;
}

然后写入文件

private void createExternalFile() {
    if (isExternalStorageAvailable()) {
        //创建外部存储的私有文件目录
        File picDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        //在私有文件目录下创建文件
        externalFile = new File(picDir, "panda.jpg");
        //打开文件的输出流
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(externalFile);
            //获取bitmap对象
            Bitmap launcherIcon = BitmapFactory.decodeResource(getResources(), R.mipmap.panda);
            //把bitmap对象压缩到输出流中
            boolean isCompressed = launcherIcon.compress(Bitmap.CompressFormat.JPEG, 100, fos);
            if (!isCompressed) {
                Log.e("david", "Failed to compress");
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

最后发送出去

    public void shareInternalFile(View view) {
        createExternalFile();
        Uri uri = Uri.fromFile(externalFile);
        Intent intent = new Intent(Intent.ACTION_SEND);
        intent.putExtra(Intent.EXTRA_STREAM, uri);
        intent.setType("image/*");
        startActivity(intent);
    }

这里我并没有通过FileProvier生成Uri,因为外部存储的文件其它应用都是可以访问的,所以我们只需要知道这个文件的路径就行,这里我们用一个Uri告知其它应用这个文件的路径。
最后我还是上一个图,让大家看到效果,并用图的最后,我们会看到内部私有文件到底存放在哪里

这里写图片描述

删除文件

当用户卸载app时候,系统会删除以下各项:
1. 内部存储中的所以文件
2. 用getExternalFilesDir()保存的外部存储的文件
但是,我们还是要自己定期删除用 getCacheDir() 创建的缓存文件。

删除文件最直接的方法就是 myFile.delete(),如果文件保存在内部存储中,可以用Context.deleteFile(fileName)

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:37006次
    • 积分:774
    • 等级:
    • 排名:千里之外
    • 原创:44篇
    • 转载:0篇
    • 译文:0篇
    • 评论:17条
    最新评论