IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android 10开发之 保存、读取图片 -> 正文阅读

[移动开发]Android 10开发之 保存、读取图片

Android 10开发之 保存、读取图片

概述

从Android 10(Q)开始,谷歌就开始修改了外部存储权限,叫做分区存储,分区存储可以分为两个目录,分别是 沙盒目录(App-specific directory公共目录(Public Directory)

沙盒目录

沙盒目录存储在 /Android/data/包名,保存文件到该目录,一般通过 Context.getExternalFilesDir() ,例如:context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) 表示路径为:/Android/data/包名/Pictures/,app一旦卸载,沙盒目录下的文件都会被删除。Android 10以上去除了WRITE_EXTERNAL_STORAGE权限,不需要这个权限就可以保存文件到沙盒目录
在这里插入图片描述

公共目录

公共目录包括 多媒体目录下载目录

公共目录的媒体文件(Photos, Images, Videos, Audio)通过MediaStore来访问,另外,MediaStore的DATA字段从Android 10开始被标记为deprecated,通过该字段获取的文件路径不再可靠,Android 10以上新增字段RELATIVE_PATH,代表文件的相对路径,在使用MediaStore保存媒体文件时,可以通过设置该字段来设置媒体文件保存的文件夹

保存文件(以图片为例)

沙盒目录

/**
     * 保存图片到沙盒目录
     * @param context 上下文
     * @param fileName 文件名
     * @param bitmap 文件
     * @return 路径,为空时表示保存失败
     */
    public static String FileSaveToInside(Context context, String fileName, Bitmap bitmap) {
        FileOutputStream fos = null;
        String path = null;
        try {
            //设置路径 /Android/data/com.panyko.filesave/Pictures/
            File folder = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
            //判断目录是否存在
            //目录不存在时自动创建
            if (folder.exists() ||folder.mkdir()) {
                File file = new File(folder, fileName);
                fos = new FileOutputStream(file);
                //写入文件
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
                fos.flush();
                path = file.getAbsolutePath();
            }
        } catch (Exception e) {
            e.printStackTrace();

        } finally {
            try {
                if (fos != null) {
                    //关闭流
                    fos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        //返回路径
        return path;
    }

保存文件到沙盒目录时,操作简单,不需要判断Android版本做兼容

公共目录

/**
     * 保存文件到公共目录
     * @param context 上下文
     * @param fileName 文件名
     * @param bitmap 文件
     * @return 路径,为空时表示保存失败
     */
    public static String fileSaveToPublic(Context context, String fileName, Bitmap bitmap) {
        String path = null;

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            //Android 10以下版本
            FileOutputStream fos = null;
            try {
                //设置路径 Pictures/
                File folder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
                //判断目录是否存在
                //目录不存在时自动创建
                if (folder.exists() || folder.mkdir()) {
                    File file = new File(folder, fileName);
                    fos = new FileOutputStream(file);
                    //写入文件
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
                    fos.flush();
                    path = file.getAbsolutePath();
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (fos != null) {
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        } else {
            //Android 10及以上版本
            
            //设置路径 Pictures/
            String folder = Environment.DIRECTORY_PICTURES;
            //设置保存参数到ContentValues中
            ContentValues values = new ContentValues();
            //设置图片名称
            values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
            //设置图片格式
            values.put(MediaStore.Images.Media.MIME_TYPE, "image/png");
            //设置图片路径
            values.put(MediaStore.Images.Media.RELATIVE_PATH, folder);
            //执行insert操作,向系统文件夹中添加文件
            //EXTERNAL_CONTENT_URI代表外部存储器,该值不变
            Uri uri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
            OutputStream os = null;
            try {
                if (uri != null) {
                    //若生成了uri,则表示该文件添加成功
                    //使用流将内容写入该uri中即可
                    os = context.getContentResolver().openOutputStream(uri);
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, os);
                    os.flush();
                    path = uri.getPath();
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (os != null) {
                    try {
                        os.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return path;
    }

Android10开始,访问公共目录的方式有改变,通过 MediaStore 来访问,因为不能完全保证Android10以下的手机能通过MediaStore方式保存文件,因此在保存文件时,根据Android版本分成两种情况(Android10以下、Android10及以上),这样稳妥

读取文件(以图片为例)

/**
     * 根据路径和名字查出文件
     * @param context 上下文
     * @param filePath 文件路径
     * @param fileName 文件名
     * @return
     */
    public static Uri FileGetFromPublic(Context context, String filePath, String fileName) {
        String queryPath;
        //判断是否有加斜杠
        if (!filePath.endsWith("/")) {
            filePath = filePath + File.separator;
        }
        //判断Android版本
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            //Android10以下
            //加上文件名
            filePath = filePath + fileName;
            //使用DATA字段做查询
            queryPath = MediaStore.Images.Media.DATA;
        } else {
            //Android10及以上
            //使用RELATIVE_PATH字段做查询
            queryPath = MediaStore.Images.Media.RELATIVE_PATH;
        }
        //拼接查询条件
        //queryPath表示文件所在路径
        //DISPLAY_NAME表示文件名
        String selection = queryPath + "=? and " + MediaStore.Images.Media.DISPLAY_NAME + "=?";
        Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{MediaStore.Files.FileColumns._ID}, selection, new String[]{filePath, fileName}, null);

        if (cursor != null && cursor.moveToFirst()) {
            //查出id
            int id = cursor.getInt(cursor.getColumnIndex(MediaStore.Images.Media._ID));
            //根据id查询URI
            Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
            return uri;
        }
        //关闭查询
        if (cursor != null) {
            cursor.close();
        }
        return null;
    }

Android 10以下是可以通过 MediaStore.Images.Media.DATA 获取文件绝对路径,Android 10 及以上DATA字段被弃用,增加了 MediaStore.Images.Media.RELATIVE_PATH获取文件相对路径。这里根据版本判断,当Android10以下时,查询DATA字段;当Android10及以上时,查询RELATIVE_PATH字段,再获取id,根据id获取URI

这里要注意下,如果是Android10及以上的,通过RELATIVE_PATH查询时,路径后面一定要检查是否加了斜杠,如果没加,一定要加斜杠;如果是Android10以下的,通过DATA查询时,路径一定要完整(包括文件名),我就是因为这个原因,一直查不到数据,后面把media数据库导出来,查看了一下才知道。

Android9,data字段:
Android9 数据表
Android11,relative_path字段:
Android11 数据表

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-10-15 11:54:32  更:2021-10-15 11:55:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:31:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码