当前位置: 首页 > news >正文

Android文件选择器[超级轻量级FilePicker测试没有问题][挣扎解决自带文件管理器获取不到绝对地址问题而是返回msf%3A1000038197]

超级轻量级FilePicker测试没有问题

本文摘录于:https://blog.csdn.net/gitblog_00365/article/details/141449437只是做学习备份之用,绝无抄袭之意,有疑惑请联系本人!
今天真的是发了疯的找文件管理器,因为调用系统自带的文件管理器老是有问题,所以越调越着急,最后发现还是FilePicker简单好用,代码仓库地址:https://gitcode.com/gh_mirrors/andr/android-filepicker/overview?utm_source=artical_gitcode&index=top&type=card&webUrl
步骤很简单,第一步添加依赖
首先,在你的项目的 build.gradle (Module) 文件中的 dependencies 块添加如下依赖:

implementation 'com.github.angads25:filepicker:1.1.0'

然后在代码黄总增加如下内容(原文内容):

import com.angads25.filepicker.model.FilePath;
import com.angads25.filepicker.view.FilePickerFragment;...// 在某个方法内启动FilePicker
private void chooseFile() {FilePickerFragment filePickerFragment = FilePickerFragment.newInstance();filePickerFragment.setFileType(FilePickerFragment.FILE_TYPE_ALL);filePickerFragment.setOnFilePathSelectedListener(new FilePickerFragment.OnFilePathSelectedListener() {@Overridepublic void onFilePathSelected(List<FilePath> filePaths) {// 处理选择的文件路径for (FilePath fp : filePaths) {Log.d("MyApp", "Selected Path: " + fp.getPath());}}});filePickerFragment.show(getSupportFragmentManager(), "FILE_PICKER");
}

我自己的代码如下:

public void onClickSelectFile(View view) {Toast.makeText(getApplicationContext(), "请选择bin格式文件", Toast.LENGTH_SHORT).show();DialogProperties properties = new DialogProperties();properties.selection_mode = DialogConfigs.SINGLE_MODE;properties.selection_type = DialogConfigs.FILE_SELECT;properties.root = new File("/sdcard");properties.error_dir = new File(DialogConfigs.DEFAULT_DIR);properties.offset = new File(DialogConfigs.DEFAULT_DIR);String[] extensions = {"bin",};properties.extensions = extensions;FilePickerDialog dialog = new FilePickerDialog(OTA_Active.this, properties);dialog.setTitle("请选择bin格式文件");dialog.setDialogSelectionListener(new DialogSelectionListener() {@Overridepublic void onSelectedFilePaths(String[] files) {// files数组包含了用户由应用程序选择的文件路径。String path=files[0];if(path!="") {int start = path.lastIndexOf("/");if (start != -1 ) {FileNameList.add(path.substring(start + 1));FilePathList.add(path);ArrayAdapter<String> array = new ArrayAdapter(OTA_Active.this, android.R.layout.simple_list_item_1, FileNameList);listview.setAdapter(array);OTA_Active.this.runOnUiThread(new Runnable() {@Overridepublic void run() {//此时已在主线程中,可以更新UI了AdapterView.OnItemClickListener onItemClickListener = listview.getOnItemClickListener();if(onItemClickListener!=null){onItemClickListener.onItemClick(listview,null,listview.getCount()-1,0);}}});}}}});dialog.show();}

本章节的源码可以从如下地址下载:https://download.csdn.net/download/chengdong1314/89943454
测试确实可行,使用起来完全没问题,视频操作演示如下:

选择文件操作

挣扎解决自带文件管理器获取不到绝对地址问题

非常无奈按照网上的方法调用系统自带的文件管理器选择文件的时候总会这样返回msf%3A1000038197之类的数据,比如如下:

content://com.android.providers.downloads.documents/document/msf%3A1000038197

本文摘录于:https://cloud.tencent.com/developer/article/2003648只是做学习备份之用,绝无抄袭之意,有疑惑请联系本人!
这里根据上面的文章调用如下函数:

    public static File uriToFileApiQ(Uri uri, Context context) {File file = null;if (uri == null) return file;//android10以上转换if (uri.getScheme().equals(ContentResolver.SCHEME_FILE)) {file = new File(uri.getPath());} else if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {//把文件复制到沙盒目录ContentResolver contentResolver = context.getContentResolver();String displayName = System.currentTimeMillis() + Math.round((Math.random() + 1) * 1000)+ "." + MimeTypeMap.getSingleton().getExtensionFromMimeType(contentResolver.getType(uri));try {InputStream is = contentResolver.openInputStream(uri);File cache = new File(context.getCacheDir().getAbsolutePath(), displayName);FileOutputStream fos = new FileOutputStream(cache);FileUtils.copy(is, fos);file = cache;fos.close();is.close();} catch (IOException e) {e.printStackTrace();}}return file;}

这样调用uriToFileApiQ函数:

protected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (resultCode == Activity.RESULT_OK) {Uri uri = data.getData();if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {//4.4以后File fi = uriToFileApiQ(this, uri);path=fi.getPath();} else {//4.4以下下系统调用方法path = getRealPathFromURI(uri);}int index = path.lastIndexOf('.');if (index > 0) {if(!("bin".equals(path.substring(index + 1))))return;}else  return;if(path!="") {int start = path.lastIndexOf("/");if (start != -1 ) {FileNameList.add(path.substring(start + 1));FilePathList.add(path);ArrayAdapter<String> array = new ArrayAdapter(OTA_Active.this, android.R.layout.simple_list_item_1, FileNameList);listview.setAdapter(array);AdapterView.OnItemClickListener onItemClickListener = listview.getOnItemClickListener();if(onItemClickListener!=null){onItemClickListener.onItemClick(listview,null,listview.getCount()-1,0);}}}}}

onActivityResult是这样引起的:

    public void onClickSelectFile(View view) {Toast.makeText(getApplicationContext(), "请选择bin格式文件", Toast.LENGTH_SHORT).show();Intent intent = new Intent(Intent.ACTION_GET_CONTENT);intent.setType("*/*");//无类型限制intent.addCategory(Intent.CATEGORY_OPENABLE);startActivityForResult(intent, 1);}

上面的uriToFileApiQ函数是有缺陷的,FileUtils.copy(is, fos);函数报错了,如果改成FileUtils.copy(is.tostring(), fos.tostring());确实编译没错了,但是拷贝到沙盒里面的文件大小是0,拷贝出错!
在这里插入图片描述
无奈啊,我这时候都放弃了,又去本文第一节去尝试了一圈,搞定了自定义文件管理器的问题,但是客户又说一定要自带的资源管理器,可以打开最近的文件,无奈只能够死磕这个问题!!!
最后找呀找,找到这篇文章:https://www.bytezonex.com/archives/b8w3-cvz.html
这里说明了原来的拷贝错误的原因:
Android 10 获取文件路径难题:/document/msf: 解决方案

许多开发者在 Android 10 设备上使用 Intent.ACTION_GET_CONTENT 获取文件路径时,都会遇到返回路径形如 /document/msf: 的情况,令人困惑不已。这并非应用本身的错误,而是 Android 10 为了加强隐私保护而采取的新策略。本文将深入剖析这一变化背后的原因,并提供一套完整的解决方案,帮助你绕过障碍,顺利获取目标文件。

从文件路径到 URI:Android 10 文件访问机制的转变
在 Android 10 之前,应用能够通过文件路径直接访问设备上的绝大多数文件,这种方式虽然便捷,但也存在着巨大的安全隐患,容易造成用户隐私泄露。为了提升系统安全性,Android 10 引入了分区存储机制,限制应用直接访问外部存储空间。

新的机制下,当应用使用 Intent.ACTION_GET_CONTENT 选择文件时,系统不再返回直接的文件路径,而是返回一个 content:// 格式的 URI。这个 URI 指向一个由 MediaStore 管理的中间层,应用无法直接从中获取文件路径,相当于在应用和真实文件之间建立了一道安全屏障。

神秘的 /document/msf: :特殊文件的安全处理
/document/msf: 正是 Android 10 返回的一种特殊 URI,它通常代表着应用选择的并非媒体文件(例如图片、视频),而是其他类型的文件。由于系统无法确定应用如何使用这些文件,为了最大程度地保护用户隐私,系统选择不直接提供文件路径,而是返回这个特殊的 URI,将文件访问权限牢牢掌握在自己手中。

ContentResolver 和 InputStream:突破封锁的利器
想要在 Android 10 上顺利获取文件内容,我们需要借助 Android 系统提供的 ContentResolver 和 InputStream 这两大利器。

操作步骤:

获取 ContentResolver: 通过 context.contentResolver 获取 ContentResolver 实例,相当于获取了与 MediaStore 通信的桥梁。
打开 InputStream: 使用 ContentResolver.openInputStream(uri) 方法,将获取的 content:// URI 传递进去,打开一个指向目标文件的 InputStream,相当于在安全屏障上打开了一条通道,文件内容将通过这条通道流向应用。
读取文件内容: 使用 InputStream 的 read() 方法,如同读取水流一般,将文件内容源源不断地读取出来,供应用使用。
整体思路就是通过InputStream 把数据从外部储存转写到沙盒来,最后修改uriToFileApiQ函数如下:

   public static File uriToFileApiQ(Context context,Uri uri) {File file = null;if(uri == null) return file;//android10以上转换if (uri.getScheme().equals(ContentResolver.SCHEME_FILE)) {file = new File(uri.getPath());} else if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {//把文件复制到沙盒目录ContentResolver contentResolver = context.getContentResolver();
//            String displayName = System.currentTimeMillis()+ Math.round((Math.random() + 1) * 1000)
//                    +"."+ MimeTypeMap.getSingleton().getExtensionFromMimeType(contentResolver.getType(uri));//            注释掉的方法可以获取到原文件的文件名,但是比较耗时Cursor cursor = contentResolver.query(uri, null, null, null, null);String displayName="";if (cursor.moveToFirst()) {displayName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));}try {InputStream in = contentResolver.openInputStream(uri);File cache = new File(context.getCacheDir().getAbsolutePath(), displayName);FileOutputStream out = new FileOutputStream(cache);//FileUtils.copy(in.toString(), out.toString());int len=-1;byte[] b=new byte[512*1024];while((len=in.read(b))!=-1){out.write(b,0,len);}file = cache;in.close();out.close();} catch (IOException e) {e.printStackTrace();}}return file;}

这里测试到拷贝过来的文件大小就对了,到此问题成功解决!
在这里插入图片描述
本章节的安卓源码从如下地址下载:https://download.csdn.net/download/chengdong1314/89943485
视频操作如下:

相关文章:

Android文件选择器[超级轻量级FilePicker测试没有问题][挣扎解决自带文件管理器获取不到绝对地址问题而是返回msf%3A1000038197]

超级轻量级FilePicker测试没有问题 本文摘录于&#xff1a;https://blog.csdn.net/gitblog_00365/article/details/141449437只是做学习备份之用&#xff0c;绝无抄袭之意&#xff0c;有疑惑请联系本人&#xff01; 今天真的是发了疯的找文件管理器,因为调用系统自带的文件管理…...

【论文速读】| RED QUEEN: 保护大语言模型免受隐蔽多轮越狱攻击

基本信息 原文标题&#xff1a;RED QUEEN: Safeguarding Large Language Models against Concealed Multi-Turn Jailbreaking 原文作者&#xff1a;Yifan Jiang, Kriti Aggarwal, Tanmay Laud, Kashif Munir, Jay Pujara, Subhabrata Mukherjee 作者单位&#xff1a;Hippocr…...

39.第二阶段x86游戏实战2-HOOK实现主线程调用

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要…...

wordpress argon主题美化方面

1、页面前端额外CSS&#xff1a; /*字体*/ font-face {font-family: myFont1; src:url(https://blog.yangmumu.com/css/fonts/Dancing.ttf) ;font-display: swap; } font-face {font-family: myFont2; src:url(https://blog.yangmumu.com/css/fonts/Regular.ttf) ;font-displa…...

qt QRadioButton详解

QRadioButton 是一个可以切换选中&#xff08;checked&#xff09;或未选中&#xff08;unchecked&#xff09;状态的选项按钮。单选按钮通常呈现给用户一个“多选一”的选择&#xff0c;即在一组单选按钮中&#xff0c;一次只能选中一个按钮。 重要方法 QRadioButton(QWidget…...

Qt 最小化,最大化,关闭窗口

Qt 最小化,最大化 在Qt中&#xff0c;你可以使用QWidget类提供的方法来实现窗口的最小化、最大化等操作。 最小化窗口 你可以使用QWidget的showMinimized()方法来最小化窗口。这将隐藏窗口并将其显示为系统托盘区域的图标。 connect(ui->btnMin,&QPushButton::click…...

【vue项目中添加告警音频提示音】

一、前提&#xff1a; 由于浏览器限制不能自动触发音频文件播放&#xff0c;所以实现此类功能时&#xff0c;需要添加触发事件&#xff0c;举例如下&#xff1a; 1、页面添加打开告警声音开关按钮 2、首次进入页面时添加交互弹窗提示&#xff1a;是否允许播放音频 以上两种方…...

百度SEO分析实用指南 提升网站搜索排名的有效策略

内容概要 在数字化时代&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;已经成为提升网站曝光度的关键工具。本指南将带您了解SEO的基本知识&#xff0c;帮助您在复杂的网络环境中立足。我们将从关键词优化开始&#xff0c;重点讲解如何选择合适的关键词来提高搜索引擎排…...

高并发场景下的性能测试方法!

在现代互联网应用中&#xff0c;高并发场景下的性能测试显得尤为重要。无论是电商平台的秒杀活动&#xff0c;还是社交应用的突发流量&#xff0c;都需要确保系统能够在高并发情况下稳定运行。本文将详细介绍高并发场景下的性能测试方法&#xff0c;并提供具体的方案和实战演练…...

杂项——USB键盘与鼠标流量分析——BUUCTF——流量分析

第一次做USB键盘与鼠标流量分析的题目&#xff0c;现在来好好做一个总结 1. 基础知识 USB流量指的是USB设备接口的流量&#xff0c;攻击者能够通过监听usb接口流量获取键盘敲击键、鼠标移动与点击、存储设备的铭文传输通信、USB无线网卡网络传输内容等等。 在正式介绍 USB H…...

Java如何实现企业微信审批流程

大家好&#xff0c;我是 V 哥。最近的一个项目中&#xff0c;用到企业微信的审批流程&#xff0c;整理出来分享给大家。在企业微信中实现审批流程可以通过调用企业微信的开放API完成&#xff0c;企业微信提供了审批应用接口&#xff0c;用于创建审批模板、发起审批流程以及获取…...

GEE app:在地图上构建一个可以查看局部的小窗

目录 简介 函数 ee.Geometry.MultiLineString(coords, proj, geodesic, maxError) Arguments: Returns: Geometry.MultiLineString getBounds(asGeoJSON) Arguments: Returns: GeoJSONGeometry|List|String setControlVisibility(all, layerList, zoomControl, scaleC…...

leetcode71:简化路径

给你一个字符串 path &#xff0c;表示指向某一文件或目录的 Unix 风格 绝对路径 &#xff08;以 / 开头&#xff09;&#xff0c;请你将其转化为 更加简洁的规范路径。 在 Unix 风格的文件系统中规则如下&#xff1a; 一个点 . 表示当前目录本身。此外&#xff0c;两个点 ..…...

nodejs入门教程4:nodejs创建第一个应用

1. 安装 Node.js 首先&#xff0c;确保你的计算机上已经安装了 Node.js。如果还没有安装&#xff0c;可以从官方网站&#xff08;https://nodejs.org&#xff09;下载并安装最新的 LTS 版本。安装完成后&#xff0c;你可以在命令行或终端中运行以下命令来验证安装&#xff1a;…...

启用 iPhone 原生的五笔输入

聊聊如何在 iOS 中使用原生的五笔输入法 本文虽然介绍的是如何添加五笔键盘&#xff0c;其实其他键盘&#xff08;双拼&#xff0c;外语键盘、第三方输入法&#xff09;也是类似的添加方式。 ‍ 使用原生的理由 虽然之前的文章列了不少第三方的五笔输入法&#xff0c;但其实…...

这个工具让你轻松开发一个带AI功能的Notion

这个工具让你轻松开发一个带AI功能的Notion Plate 是一款由 AI 加持的富文本编辑器&#xff0c;旨在帮助开发者创建功能强大的 WYSIWYG 文本编辑工具。本文将介绍 Plate 的基本信息、特点、以及如何快速上手使用。 软件简介 Plate 由 udecode 开发&#xff0c;基于 React 和 S…...

光耦合器的关键作用和创新---腾恩科技

光耦合器或光隔离器已成为电路中必不可少的器件&#xff0c;它允许信号在无需直接电接触的情况下跨不同电压域传输。这种隔离能力对于保护低压元件免受高压电路的潜在损坏至关重要。本文将仔细研究光耦合器在当今技术中发挥的独特作用&#xff0c;并探讨其在各种应用中不断扩展…...

穿越死锁的迷雾:pthread_mutex_lock的终极挑战与破解策略

穿越死锁的迷雾:pthread_mutex_lock的终极挑战与破解策略 一、死锁的基本概念二、pthread_mutex_lock 出现死锁的原因三、pthread_mutex_lock 出现死锁的表现四、处理pthread_mutex_lock 出现死锁的方法1. 避免死锁1.1 遵循锁的顺序原则1.2 使用定时锁1.3 使用尝试锁1.4 使用递…...

Dockerfile制作Oracle19c镜像

Dockerfile文件 cat > Dockerfile << EOF # 使用 Oracle Linux 8 作为基础镜像 FROM oraclelinux:8# 复制 Oracle 19c 安装包 COPY oracle-database-ee-19c-1.0-1.x86_64.rpm /tmp/# 安装 Oracle 19c 数据库和依赖 RUN yum localinstall -y /tmp/oracle-database-ee-…...

【时间之外】IT人求职和创业应知【23】

目录 新闻一:央行发布首个买断式逆回购交易公告 新闻二:2024CCF科技创业大赛报名截止 新闻三:BNB Chain将在迪拜主办第四届BNB孵化联盟(BIA) 认知决定你的赚钱能力。以下是今天可能影响你求职和创业的热点新闻: 今日关键字:TCL两连扳,已经跑了,我的认知就到此了 新…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

Java - Mysql数据类型对应

Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中&#xff0c;高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司&#xff0c;近期做出了一个重大技术决策&#xff1a;弃用长期使用的 Nginx&#xff0c;转而采用其内部开发…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...