- 外文名
- File
- 英式音标
- [faɪl]
- 词 性
- 名词、及物动词、不及物动词
- 美式音标
- [faɪl]
-
关于input type=“file”的及其files对象的深层探究
2018-05-11 16:57:03我们都知道,html5中有个input type=file元素。用该元素可以实现页面上传文件的功能 但一般的做法只是简单的在表单中操作,我来研究一下深层东西 ...$("input[name='file1']").change( function(e){ console.log...我们都知道,html5中有个input type=file元素。用该元素可以实现页面上传文件的功能
但一般的做法只是简单的在表单中操作,我来研究一下深层东西
想要了解它,就要知道它的内置对象,files
页面上写一个input,然后选俩个图片,打印这个input对象
$("input[name='file1']").change( function(e){ console.log($("input[name='file1']")) })
发现有下列值,在0中,有一个files对象
我们发现input选择的文件被记录到了这个对象中,这个是fileList对象,是一个只读对象,不能修改
因为它不能修改,所以很难实现对已选中多个文件的删除某个文件等操作
里面记录了文件的name,size,type,和修改时间等,可知这个对象只存放了一些文件的信息,相当于是本地文件的索引,并不是把文件放到input中了,上传文件时它会再去找到实际的本地文件
fileList数组包含多个File对象,File对象是继承与Blob对象的,关于file,url,blob,dataUrl可以详细查查
一般url可以是本地地址,http地址等
blob对象一般的形式是:blob:http://192.168.100.151:8080/1148dcd6-952e-4478-823d-21b37e537c2f,属于浏览器对象
dataUrl 一直格式是:以data:image/jpeg;base64,这种类似形式打头的一串很长的字符串。
这三种形式在img标签中src属性都可以调用。
File对象有name,size,lastModified属性
File对象的创建:
var file1=new File([blob], "aa.png",{type:"image/jpg"}); //第一个参数是Blob对象或者dataUrl,第二个参数是文件名,三个参数可选,规定文件类型
注意:第一个参数必须是对象,不能是转换成的字符串,比如uniapp或者微信小程序的chooseImage方法返回的blob的url,他是一个字符串,这样生成的File对象只是将url字符串变成文件了,不是文件本身!!!
想把blob字符串变成Blob对象,可以用es6的:const blob = await fetch(image.path).then(r => r.blob())
或者用传统的XHR或者ajax也行,就是把blob对象根据url给获取出来就行。
利用这个files对象,我们可以实现很多功能,例如:
一.选择图片未经后端显示预览图片
方法1:利用window的url工具将文件生成url,再将url赋值给img的src属性,显示出选中图像
顺便提一下,input中控制选中类型加一个accept属性就行了,只会显示设定的文件类型
<input id="file1" type="file" name="file1" multiple="multiple" accept=".doc,.jpg">
$('.fbpj-camera').change(function(event) { //$('.dianpuzhuangxiu .addmokuai .block .shuoming1 .pic .pic1').children().remove(); // 根据这个 <input> 获取文件的 HTML5 js 对象 var files = event.target.files, file; if (files && files.length > 0) { // 获取目前上传的文件 file = files[0]; // 来在控制台看看到底这个对象是什么 console.log(file); // 那么我们可以做一下诸如文件大小校验的动作 if(file.size > 1024 * 1024 * 2) { alert('图片大小不能超过 2MB!'); return false; } // !!!!!! // 下面是关键的关键,通过这个 file 对象生成一个可用的图像 URL // 获取 window 的 URL 工具 var URL = window.URL || window.webkitURL; // 通过 file 生成目标 url var imgURL = URL.createObjectURL(file); // 用这个 URL 产生一个 <img> 将其显示出来 $('.fbpj .container').prev().find("img").attr('src', imgURL); // 使用下面这句可以在内存中释放对此 url 的伺服,跑了之后那个 URL 就无效了 //URL.revokeObjectURL(imgURL); } });
方法二:利用html5的FileReader()读取文件
*前提是浏览器支持的话
if(window.FileReader) { var fr = new FileReader(); // add your code here } else { alert("Not supported by your browser!"); }
<script type="text/javascript"> function showPreview(source) { var file = source.files[0]; if(window.FileReader) { var fr = new FileReader(); fr.onloadend = function(e) { document.getElementById("portrait").src = e.target.result; }; fr.readAsDataURL(file); //也是利用将图片作为url读出 } } </script> <input type="file" name="file" onchange="showPreview(this)" /> <img id="portrait" src="" width="70" height="75">
FileReader还有一些其他用法
<html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <meta name="author" content="oscar999"> <title></title> <script> function handleFiles(files) { if(files.length) { var file = files[0]; var reader = new FileReader(); reader.onload = function() { document.getElementById("filecontent").innerHTML = this.result; }; reader.readAsText(file); //作为字符串读出 //reader.readAsText(file,'gb2312'); //默认是用utf-8格式输出的,想指定输出格式就再添加一个参数,像txt的ANSI格式只能用国标才能显示出来 } } </script> </head> <body> <input type="file" id="file" onchange="handleFiles(this.files)"/> <div id="filecontent"></div> </body> </html>
readAsText一般只能读取txt,html等等文件,局限性较大,比如想要前端读excel文件,由于解决文件编码问题较为复杂,需要用到js-xlsx插件,具体可百度方法。
常用API:
FileReader.readAsDataURL(File) //转换成base64格式
FileReader.readAsText() //转换成字符串格式
FileReader.readAsArrayBuffer(File) //转换成ArrayBuffer格式
FileReader.readAsBinaryString(File) //转换成原始二进制格式(貌似已被废除)
FileReader.onload = function (e) { console.log(e.target.result) } //在上述读取事件完成时触发
二.文件拖拽的方法保存文件
关于文件拖拽下面有注释,我主要说一下怎么给用js给input赋值,而不是手动去选文件
因为拖拽的区域只是一个div,无法进行上传操作,所以需要加一个form和input,让拖拽进去的文件进入input中。
取出files后,用$("#file1")[0].files=files;将文件赋值给input,注意赋值的必须是fileList对象,不要试图只放进去一个文件,fileList只读。
然后用h5中的FormData将form转化,提交即可
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <style> .container{ width:300px;height: 300px; border:2px dashed #ddd; text-align: center; padding:50px; } </style> <title> 培训活动列表 </title> </head> <body> <div class="container"> 拖拽进入 </div> <form id="form1" method="post" enctype="multipart/form-data"> <input type="file" name="file1" id="file1" value="" /> </form> <script type="text/javascript"> $('.container').bind('dragenter dragover', ignoreDrag); $(".container").on({drop:function(e){ var flag=true; e.preventDefault(); //jquery的file要去e.originalEvent里面拿,拖拽获取files的方式与input的不同 var files = e.originalEvent.dataTransfer.files; //var files = e.dataTransfer.files; 原生的话这样就可以获取 for(var i=0;i<files.length;i++){ myFileReader(files[i],function(result,file){ if(result){ //文件 console.log(file.name) }else{ //文件夹 console.log("不要上传文件夹") flag=false; } }); } if(flag){ $("#file1")[0].files=files; //关键:将取到的文件赋值给input,用于ajax提交文件!!! var formData = new FormData($("#form1")[0]); $.ajax({ url : "/it/orderManage/saveActivity", type : 'POST', data : formData, // 告诉jQuery不要去处理发送的数据 processData : false, // 告诉jQuery不要去设置Content-Type请求头 contentType : false, async : true, success : function(ret) { //alert("上传成功") if(ret){ $("#trainInfoModal").modal("hide"); layer.alert("保存成功") $('#orderTable').bootstrapTable("refresh"); $("#trainInfoModal input").val(""); $("#trainInfoModal textarea").val(""); } } }); } console.log(files); }}) function ignoreDrag(e) {e.originalEvent.stopPropagation(); e.originalEvent.preventDefault(); } function myFileReader(file, callback){ if(!window.FileReader){ callback(true,file); return false; } var fr = new FileReader(); fr.readAsDataURL(file); fr.onload=function(e){ callback(true,file); } fr.onerror=function(e){ //不好判断是否是文件夹,通过上传报错可以判断是文件夹 callback(false,file); } return true; }; </script> </body> </html>
后台获取文件还是用MutipartFile[]接收
public String saveActivity(@RequestParam HashMap<String, String> param, //@RequestParam(value = "banner") MultipartFile[] files, @RequestParam(value = "file1") MultipartFile[] file1, HttpServletRequest request, String fileNames, String TID, HttpServletRequest req) {
三.vue+axios 上传文件无论ajax还是axios,都不是直接用表单提交的,都是 要用 new FormData()转化一下。
所以axios方法与ajax方法类似
<input type="file" class="inputBtn" @change="uploadMarketingForm">
uploadMarketingForm(e){ console.log(e) var fileName=e.target.files[0].name; //文件名 var fileSize=e.target.files[0].size; //文件大小 var param = new FormData(); //添加表单参数,如果后台用文件数组接收 //param.append("file", e.target.files); //如果后台只接收单一文件 param.append("file", e.target.files[0]); //设置表头类型 const config = { headers: { "Content-Type": "multipart/form-data" } }; this.axios.post("/.../uploadTest", param, config).then(res => { console.log(res); }); },
在java spring mvc中还是这么接收
@ResponseBody @RequestMapping(value = "uploadTest", produces = "text/plain;charset=UTF-8") public String uploadTest(@RequestParam Map<String,String> param,@RequestParam(value = "file") MultipartFile[] file1, HttpServletRequest request) throws IOException { RetBase retBase = new RetBase(); //文件可以在参数中用MultipartFile[](多文件) 或者 MultipartFile (单一文件)接收 //也可以像这样在request中接收 MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; MultipartFile multifile = multipartRequest.getFile("file"); // 通过参数名获取指定文件 String fileName = multifile.getOriginalFilename(); // 获取文件后缀 String prefix=fileName.substring(fileName.lastIndexOf(".")); // 用uuid作为文件名,防止生成的临时文件重复 final File file = File.createTempFile(UUID.randomUUID().toString(), prefix); // MultipartFile to File return JSON.toJSONString(retBase, SerializerFeature.WriteMapNullValue); }
-
简化 java.io.File 类的源码和方法
2020-09-24 06:58:08public class File implements Serializable, Comparable<File>{ private final String path;// 存储路径 private final transient int prefixLength;// 前缀长度 private static final FileSystem fs = ...public class File implements Serializable, Comparable<File>{ private final String path;// 存储路径 private final transient int prefixLength;// 前缀长度 private static final FileSystem fs = DefaultFileSystem.getFileSystem(); //获取文件系统,例如ntfs、ext3等 public static final char separatorChar = fs.getSeparator(); // 路径分割符 public static final char pathSeparatorChar = fs.getPathSeparator(); // 文件系统的路径分割符 public static final String separator = "" + separatorChar; // 返回字符串类型的 public static final String pathSeparator = "" + pathSeparatorChar; // 存储路径 private static enum PathStatus { INVALID, CHECKED };// 文件状态 private transient PathStatus status = null; // 默认为null private static final jdk.internal.misc.Unsafe UNSAFE = jdk.internal.misc.Unsafe.getUnsafe(); private static final long PATH_OFFSET = UNSAFE.objectFieldOffset(File.class, "path"); private static final long PREFIX_LENGTH_OFFSET = UNSAFE.objectFieldOffset(File.class, "prefixLength"); @java.io.Serial private static final long serialVersionUID = 301077366599181567L; // 序列化版本号 private transient volatile Path filePath; //文件路径对象 /** * 构造方法 */ public File(String pathname) {} // 最常用的 private File(String pathname, int prefixLength) {} private File(String child, File parent) {} public File(String parent, String child) {} public File(File parent, String child) {} public File(URI uri) {} /** * 文件状态操作 */ public boolean canRead() {} // 文件是否可读 public boolean canWrite() {} // 文件是否可写 public boolean isDirectory() {} // 是否是目录 public boolean exists() {} // 文件是否已存在 public boolean isFile() {} // 是否是文件 public boolean isHidden() {} // 是否是隐藏文件 final boolean isInvalid() {} // 判断文件状态是否是无效的,无效返回true public boolean setLastModified(long time) {}// 设置修改文件的时间 public long lastModified() {} // 返回上一次修改文件时间戳 public boolean setReadOnly() {} // 设置为只读,true表示成功设置,flase表示失败 public boolean setWritable(boolean writable, boolean ownerOnly) {} //设置为可写 public boolean setWritable(boolean writable) {} // 设置为可写 public boolean setReadable(boolean readable, boolean ownerOnly) {}// 设置为可读 public boolean setReadable(boolean readable) {}// 设置为可读 public boolean setExecutable(boolean executable, boolean ownerOnly) {}// 设置为可执行 public boolean setExecutable(boolean executable) {} /** * 常用文件操作 */ public long length() {} // 返回文件大小 public String getName() {} // 获取文件名称 public boolean renameTo(File dest) {} // 重命名文件 public boolean delete() {} // 删除文件 public String getParent() {} // 获取父级目录名 public File getParentFile() {} //返回父级目录 public String getPath() {} //返回文件路径 public boolean isAbsolute() {} // 绝对路径返回true public String getAbsolutePath(){} // 返回文件的绝对路径 public File getAbsoluteFile() {} // 返回绝对路径文件 public String getCanonicalPath() {} // 返回规范的文件路径 public Path toPath() {} // path字符串转Path对象 int getPrefixLength() {} // 获取文件前缀名长度值 /** * 常用的目录操作 * 获取目录下所有文件、创建目录 */ public static File[] listRoots() {} // 返回根目录 public String[] list() {} // 返回path目录下的所有文件名 public String[] list(FilenameFilter filter) {} // 返回经过过滤后的所有文件名 public File[] listFiles() {} // 获取目录下的所有文件对象 public File[] listFiles(FilenameFilter filter) {} // 获得过滤后的文件对象 public File[] listFiles(FileFilter filter) {} // 获得过滤后的文件对象 public boolean mkdir() {}// 目录不存在则创建目录并返回true,否则返回false public boolean mkdirs() {}// 创建文件夹,父级目录不存在也会创建父级目录 public boolean equals(Object obj) {} // 判断文件是否是同一个文件 public String toString() {} // 返回文件路径 public int compareTo(File pathname) {} //比较pathname文件是否与当前文件相同 public int hashCode() {} // 返回当前文件的hash值 /** * 下面的都是不常用方法 * 可以不用看 */ public boolean createNewFile() throws IOException {} // 文件已存在返回flase,不存在则创建并返回true public void deleteOnExit() {} // 程序终止时(jvm退出时)删除文件 private static String slashify(String path, boolean isDirectory) {} // isDirectory=true返回标准化的路径 public File getCanonicalFile() throws IOException {}// 返回规范的文件 @Deprecated public URL toURL() throws MalformedURLException {}// 返回等效文件URL的URL对象 public URI toURI() {} // 转换为uri public boolean canExecute() {} // 是否可执行 public long getTotalSpace() {} // 获取文件大小(byte) public long getFreeSpace() {} // 获取文件剩余空间大小 public long getUsableSpace() {} //获取可使用空间大小 public static File createTempFile(String prefix, String suffix,File directory) throws IOException {} // 指定路径创建临时文件 public static File createTempFile(String prefix, String suffix) throws IOException {} // 当前路径下创建临时文件 // 序列化 @java.io.Serial private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException {} // 反序列化 @java.io.Serial private synchronized void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {} private static class TempDirectory { private static final SecureRandom random = new SecureRandom(); private TempDirectory() { } private static final File tmpdir = new File(GetPropertyAction.privilegedGetProperty("java.io.tmpdir")); static File location() {} // 返回临时目录对象 private static int shortenSubName(int subNameLength, int excess,int nameMin) {} // static File generateFile(String prefix, String suffix, File dir) throws IOException{} // 生称文件 } }
-
js清空input file的值
2017-08-07 16:11:15今天在做选择本地图片上传的功能时遇到一个问题,第一次选择图片完成会触发onchange事件,获取文件后动态在界面上创建img标签展示,这个过程没有问题,问题出在当把创建的img元素节点删除后,再点file控件选中同一个...在做选择本地图片上传的功能时遇到一个问题,第一次点file按钮选择图片完成会触发onchange事件,获取文件后动态在界面上创建img标签展示,但把创建的img元素节点删除后,再点file按钮选择同一个文件后发现图片并没有被重新创建出来。
分析了原因:因为上一次选择的文件与本次选择的是同一个文件,两次的路径值相同,值没有改变所以导致file不会触发onchange事件,因此需要每次创建完img后重置file的value或者重置file的dom来解决这个问题。
解决方法一:
每次创建完img后把file的value值重置为空字符串var file = document.getElementById('file'); file.value = ''; //file的value值只能设置为空字符串
注意:浏览器的安全机制不允许直接用js修改file的value为空字符串以外的值,强制修改会报以下错误:
VM4061:1 Uncaught DOMException: Failed to set the ‘value’ property on ‘HTMLInputElement’: This input element accepts a filename, which may only be programmatically set to the empty string.
解决方法二:
每次创建完img后把file的outerHTML重置var file = document.getElementById('file'); file.outerHTML = file.outerHTML; //重置了file的outerHTML
-
Android N 7.0 应用间共享文件(FileProvider)
2017-10-20 20:07:03Android N 之前的 Uri 常规Uri有两种: 媒体文件的Uri是content://, 表示这是...这个uri是通过Uri.fromFile(File file)方法生成。 Android N 之前,这些uri可以传递到其他应用。 Android N 中共享文件 AndroidAndroid N 之前的 Uri
常规Uri有两种:
- 媒体文件的Uri是content://, 表示这是一个数据库数据。去数据库查询正常返回。
- 其他的文件Uri是file://, 表示这个是一个文件。这个uri是通过Uri.fromFile(File file)方法生成。
Android N 之前,这些uri可以传递到其他应用。
Android N 中共享文件
Android N 系统,Android 框架执行的 StrictMode,API 禁止向您的应用外公开 file://URI。
如果一项包含文件 URI 的 Intent 离开您的应用,应用会停止运行,并出现 FileUriExposedException异常。官方文档在Android 7.0 行为变更进行了详细说明android.os.FileUriExposedException: file:///storage/emulated/0/Download/appName-2.3.0.apk exposed beyond app through Intent.getData()
若要在应用间共享文件,您应发送一项 content://URI(代替file://URI),并授予 URI 临时访问权限。
FileProvider这个类就是把一个文件File,转换为 content://URI的
FileProvider是ContentProvider子类,所以FileProvider的使用方法,和ContentProvider使用基本上是一样的
如何共享文件,简单5步:
1、在AndroidManifest.xml中<application>标签下声明一个provider
<provider android:name="android.support.v4.content.FileProvider" android:authorities="app的包名.fileProvider" android:grantUriPermissions="true" android:exported="false"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
注意:
authorities:app的包名.fileProvider
grantUriPermissions:必须是true,表示授予 URI 临时访问权限 ( readPermission, writePermission, and permission attributes)
exported:true: The provider is available to other applications. false: The provider is not available to other applications.
resource:自定义的xml文件(下面会介绍)2、在res目录下新建一个xml文件夹,并且新建一个file_paths的xml文件(如下图)
3、打开file_paths.xml文件,添加指定的分享目录:
file_paths.xml 是这样的
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <root-path name="root" path="" /> <files-path name="files" path="" /> <cache-path name="cache" path="" /> <external-path name="external" path="" /> <external-files-path name="name" path="path" /> <external-cache-path name="name" path="path" /> </paths>
在paths节点内部支持以下几个子节点,分别为:
<root-path/> 代表设备的根目录new File("/");
<files-path/>代表: Context.getFilesDir()
<external-path/>代表: Environment.getExternalStorageDirectory()
<cache-path/>代表: getCacheDir()
<external-files-path>代表context.getExternalFilesDirs()
<external-cache-path>代表getExternalCacheDirs()每个节点都支持两个属性:
name:给这个访问路径起个名字
path:需要临时授权访问的相对路径(.代表所有路径)<external-path name="external" path="pics" />
path即为代表external-path目录下的子目录,目录为:Environment.getExternalStorageDirectory()/pics,其他同理。
下面举一些例子:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!--代表外部存储区域的根目录下的文件 Environment.getExternalStorageDirectory()/DCIM/camerademo目录--> <external-path name="DCIM" path="DCIM/camerademo" /> <!--代表外部存储区域的根目录下的文件 Environment.getExternalStorageDirectory()/目录--> <external-path path="." name="external_storage_root" /> <!--代表外部存储区域的根目录下的文件 Environment.getExternalStorageDirectory()/Pictures/camerademo目录--> <external-path name="Pictures" path="Pictures/camerademo" /> <!--代表app 私有的存储区域 Context.getFilesDir()目录下的images目录 /data/user/0/com.hm.camerademo/files/images--> <files-path name="private_files" path="images" /> <!--代表app 私有的存储区域 Context.getCacheDir()目录下的images目录 /data/user/0/com.hm.camerademo/cache/images--> <cache-path name="private_cache" path="images" /> <!--代表app 外部存储区域根目录下的文件 Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)目录下的Pictures目录--> <!--/storage/emulated/0/Android/data/com.xx.xxxxxx/files/Pictures--> <external-files-path name="external_files" path="Pictures" /> <!--代表app 外部存储区域根目录下的文件 Context.getExternalCacheDir目录下的images目录--> <!--/storage/emulated/0/Android/data/com.xx.xxxxxx/cache/images--> <external-cache-path name="external_cache" path="." /> </paths>
下面的例子使用SDCard,代码如下:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external" path="" /> </paths>
4、FileProvider API的使用
/** * 打开相机拍照 * * @param activity * @return */ public static void openCamera(Activity activity) { String filename = new SimpleDateFormat("yyyyMMdd-HHmmss", Locale.CHINA) .format(new Date()) + ".png"; File pictureFile = new File(Environment.getExternalStorageDirectory(), filename ); Intent mIntent = new Intent(); mIntent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { Uri contentUri = FileProvider.getUriForFile(activity, "app的包名.fileProvider", pictureFile ); //拍照结果输出到这个uri对应的file中 mIntent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri); //对这个uri进行授权 //mIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //对这个uri进行授权 mIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); } else { //拍照结果输出到这个uri对应的file中 mIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(pictureFile )); } mIntent.putExtra(MediaStore.Images.Media.ORIENTATION, 0); activity.startActivityForResult(mIntent, REQUEST_CAMERA_IMAGE); }
核心代码就这一行了~
Uri contentUri = FileProvider.getUriForFile(activity, "app的包名.fileProvider", pictureFile );
-
第二个参数就是我们在androidManife.xml 中的provider的参数authorities
-
第三个参数是指定的文件File
生成的uri:
content://com.xuexuan.fileprovider/external/20171201-094017.png
可以看到格式为:
content://authorities/paths中name的值/文件的相对路径
,即name隐藏了可存储的文件夹路径。这里需要多说一点,Uri 的最终路径,与file和path有很大关系
如果file的路径完全包含path路径的,则显示path路径+文件的相对路径,如下:
path路径
<external-path name="my_external" path="customscamera" />
file路径
/storage/emulated/0/customscamera/1534305129374.jpg
则 Uri 为:
content://com.xuexuan.fileprovider/my_external/customscamera/1534305129374.jpg
如果file的路径不完全包含path路径的,则显示文件的绝对路径,如下:
path路径
<external-path name="my_external" path="123" />
file路径
/storage/emulated/0/customscamera/1534305129374.jpg
则 Uri 为:
content://com.futureway.blealarm.fileProvider/profile_photo/storage/emulated/0/customscamera/1534305129374.jpg
5、对URI进行授权
第4步的代码,有一行注释是:对这个uri进行授权。
授权有两种方式:
- Intent.addFlags,该方式主要用于针对intent.setData,setDataAndType以及setClipData相关方式传递uri的。
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
2、使用函数进行授权和移除权限
-
grantUriPermission(String toPackage, Uri uri,
int modeFlags)函数来进行授权 -
revokeUriPermission(Uri uri, int modeFlags);移除权限
方式二较为麻烦,因为需要指定目标应用包名,很多时候并不清楚,所以需要通过PackageManager进行查找到所有匹配的应用,全部进行授权。不过更为稳妥~
List<ResolveInfo> resInfoList = context.getPackageManager() .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); for (ResolveInfo resolveInfo : resInfoList) { String packageName = resolveInfo.activityInfo.packageName; context.grantUriPermission(packageName, uri, flag); }
如果没有授权,可能会遇到这样的错误
java.lang.SecurityException: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{18570a 27107:com.google.android.packageinstaller/u0a26} (pid=27107, uid=10026) that is not exported from UID 10004
以下这两个问题,可参考这篇文章
-
为什么在Android 7 设备上,Intent的action为ACTION_IMAGE_CAPTURE,不进行授权,不会遇到Permission Denial的问题
-
为什么Android 4.4设备遇到权限问题,不通过addFlags这种方式解决
错误分析
报错
java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/DCIM/camerademo/20170226_110056248725175.jpg
分析
在生成Uri 的时候,指定的文件所在的路径没有包含在path所指定的路径中
疑惑
遇到这样一个到现在没有理解的问题,在小米6,MIUI 9.0 上面,使用下面的代码,进行图片的裁剪。
1、如果不使用下面的函数授权,就会出现
java.lang.SecurityException: Permission Denial
的错误2、使用了下面的函数授权,可以正常返回。但是返回的数据是null。但是在指定路径有裁剪后的照片输出。
有大神知道问题的原因,帮忙在评论里指导我一下,十分感谢
/*** * 裁剪图片 * @param activity Activity * @param uri 图片的Uri */ public static void cropPicture(Activity activity, Uri uri) { Intent intent = new Intent("com.android.camera.action.CROP"); intent.putExtra("crop", "true");// 才能出剪辑的小方框,不然没有剪辑功能,只能选取图片 intent.putExtra("aspectX", 1); // 放大缩小比例的X intent.putExtra("aspectY", 1);// 放大缩小比例的X 这里的比例为: 1:1 intent.putExtra("outputX", 120); //这个是限制输出图片大小 intent.putExtra("outputY", 120); intent.putExtra("return-data", false); //切图大小不足输出,无黑框 intent.putExtra("scale", true); intent.putExtra("scaleUpIfNeeded", true); Log.e("FaceUtil", "图片path:" + uri.toString()); File imageFile = new File(uri.getPath()); //输出图片的路径 File outputImageFile = new File(Environment.getExternalStorageDirectory(), "picture" + System.currentTimeMillis() / 1000 + ".jpg"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); Uri contentUri = FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".fileProvider", imageFile); Uri outputUri = FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".fileProvider", outputImageFile); intent.setDataAndType(contentUri, "image/*"); //使用函数授权,所有的包名 List<ResolveInfo> resInfoList = activity.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); for (ResolveInfo resolveInfo : resInfoList) { String packageName = resolveInfo.activityInfo.packageName; activity.grantUriPermission(packageName, outputUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION); } //裁剪后的图片,将被保存在这个uri中 intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri); } else { //裁剪后的图片,将被保存在这个uri中 intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(outputImageFile)); intent.setDataAndType(uri, "image/*"); } intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString()); activity.startActivityForResult(intent, REQUEST_CROP_IMAGE); }
请点赞、收藏,感谢大家的支持,有任何疑问可在评论区回复
参考:Android 7.0 行为变更 通过FileProvider在应用间共享文件吧
https://developer.android.com/guide/topics/manifest/provider-element.html
Android7.0须知–应用间共享文件(FileProvider)
解决 Android N 7.0 上 报错:android.os.FileUriExposedException
FileProvider无法获取外置SD卡问题解决方案 | Failed to find configured root that contains
FileProvider 的使用(Failed to find configured root that contains/storage/emulated/0/DCIM/ )
-
Python 相对路径问题:“No such file or directory
2019-08-04 09:59:09如果你取相对路径不是在主文件里,可能就会有相对路径问题:"No such file or directory"。 因为 python 的相对路径,相对的都是主文件。 main.py 是主文件。 conf.py 里引用 config.txt 用相对路径。 如果用 . ... -
MultipartFile转File
2019-06-19 18:45:05前端传过来MultipartFile,后端转为file后删除本地缓存文件 后台接收的需要转换为一个File类型的 接受前端文件: MultipartFile file111 = ((MultipartHttpServletRequest) httpServletRequest).getFile("前端传... -
IntelliJ IDEA :decompiled.class file bytecode version:52.0(java 8) ,open source file.
2016-10-19 11:48:15decompiled.class file bytecode version:52.0(java 8) , open source file. 翻译一下上面的意思:(反编译 .class文件中的字节码 到Java 8 版本) 打开源文件 其实这个时候,你就得注意一下,你看到... -
(windows) 开机时出现“checking file system on C” 问题原因及解决方法
2018-09-08 10:54:43前言 这是windows7中常见的问题,下面介绍的就是它的问题原因及解决方法。 ...问题原因及解决方法 ...也许开机时看见一团不知道什么意思的英文,大脑一定是懵逼的,想着电脑是不是坏了,...checking file system o... -
Java中isFile()与exists()的区别
2018-07-31 11:44:36isFile()作为标题发表不成功= = 把括号去了 1.在Linux中,区别比较明显,对于/dev/null 文件是特殊文件,isFile返回false,而exist返回true 2.isFile() public boolean isFile()测试此抽象路径名表示的文件是否... -
CMakeFile命令之file
2018-11-23 11:11:42file:文件操作命令. file(WRITE filename "message towrite"... ) WRITE 将一则信息写入文件’filename’中,如果该文件存在,它会覆盖它,如果不存在,它会创建该文件。 file(APPEND filename &... -
-
MultipartFile与File的一些事
2019-01-05 17:29:27在实现这个需求的过程中就用得到了MultipartFile与File,而且我对前一个也不是很熟悉。记录一下 什么是MultipartFile MultipartFile是spring类型,代表HTML中form data方式上传的文件,包含二进制数据+文件名称。... -
Python运行报错FileNotFoundError [Errno 2] File b‘xxx.csv’ does not exist b‘xxx.csv’
2020-05-29 02:31:45FileNotFoundError [Errno 2] File b'xxx.csv' does not exist b'xxx.csv' 文章目录一、 问题描述二、 问题分析三、 解决方法3.1 方法一3.2 方法二 一、 问题描述 运行代码的时候,弹出以下错误提示 self._reader ... -
xml文件下载报This XML file does not appear to have any style information associated with it....
2019-06-19 10:46:52xml文件下载报This XML file does not appear to have any style information associated with it. The document 可能是原文件缺失了文件声明 正常的xml文件 <?xml version='1.0' encoding='UTF-8'?> <... -
Java中将File转化为MultipartFile的方法
2018-08-15 14:17:28import java.io.File; import java.io.FileInputStream; import org.springframework.web.multipart.MultipartFile; import org.springframework.mock.web.MockMultipartFile; import org.apache.h... -
JAVA 将MultipartFile file转换成为File
2019-10-31 13:14:04public static File MultipartFileToFile(MultipartFile multiFile) { // 获取文件名 String fileName = multiFile.getOriginalFilename(); // 获取文件后缀 String prefix = fileName.su... -
File协议
2017-12-22 22:01:571.file协议 中文意思:本地文件传输协议 什么是File:File协议主要用于访问本地计算机中的文件,就如同在Windows资源管理器中打开文件一样。 如何使用File:要使用File协议,基本的格式如下:file:///文件路径,... -
java File中File.exists() 与 File.isFile()区别?
2016-12-09 18:05:33使用File.isFile()方法返回结果是false使用File.exists()方法返回结果是true也就是说如果是我们常见的普通文件,两者是没多少区别的!区别只在于特殊文件中。Use File.exists() when dealing with special files ... -
解决cannot open shared object file: No such file or directory
2019-06-12 11:24:19cannot open shared object file: No such file or directory 解决办法: 1、此时ldd xxx查看依赖缺少哪些库 libmysqlcppconn.so.7 => not found libboost_system.so.1.64.0 => not found 2、... -
Android之FileProvider :通过FileProvider来获取content uri
2018-08-07 11:41:25最近在测试FileProvider相关功能的时候,在从自定义相册选择图片通过FileProvider来获取content uri的时候程序突然崩溃了,报出了 Failed to find configured root that contains xxxx 的错误,一开始以为是自己... -
安装 ANSYS19.0 最后一步 Add a License File 出现 Did not upload file - Error
2019-08-16 15:52:52Did not upload file - Error: The hostid in the license file is not a valid hostid for this license server machine. 原因:生成 license.txt 时 host ID 填写的不对 在 License Management Center 中的 Get ... -
[开发技巧]·h5文件读取失败分析-OSError:Unable to open file (file signature not found)
2019-04-13 00:11:10[开发技巧]·h5文件读取失败分析-OSError:Unable to open file (file signature not found) 使用keras在加载网络网络参数的时候出现这个问题 File "h5py\h5f.pyx", line 78, in h5py.h5f.open OSError: Unable... -
muduo之LogFile
2019-10-28 21:04:12muduo之LogFile,LogFile是控制日志怎么和文件打交道,其中包含常用的对日志处理的一些操作。AsyncLogging异步日志需要调用LogFile的接口将日志写入文件,其中包含了AppendFile类,相当于再AppendFile上面封装了一层... -
Spark中加载本地(或者hdfs)文件以及SparkContext实例的textFile使用
2015-07-12 21:26:51默认是从hdfs读取文件,也可以指定sc.textFile("路径").在路径前面加上hdfs://表示从hdfs文件系统上读 本地文件读取 sc.textFile("路径").在路径前面加上file:// 表示从本地文件系统读,如file:///home/user/... -
Java中File使用--创建文件
2019-06-20 14:33:451.错误示范1,输出的是创建文件夹 D:\filepath\test\test.txt。 public class FileTest { public static void main(String[] args) throws IOException { String fileName = "test.txt";... File testFile = new... -
成功解决NameError: name 'file' is not defined
2018-12-08 16:13:36成功解决NameError: name 'file' is not defined 目录 解决问题 解决思路 解决方法 解决问题 NameError: name 'file' is not defined 解决思路 原因:python版本升级,函数使用有所变化 ... -
Spring Boot:The field file exceeds its maximum permitted size of 1048576 bytes.
2017-01-12 21:15:50Spring Boot做文件上传时出现了The field file exceeds its maximum permitted size of 1048576 bytes.错误,显示文件的大小超出了允许的范围。查看了官方文档,原来Spring Boot工程嵌入的tomcat限制了请求的文件... -
File判断文件是否存在及file常用API
2018-01-04 09:51:04File file = new File("D:\\file"); System.out.println(file.exists()); 如果输出结果为true,则存在D:\file