Uri转路径 Uri转文件

2,457 阅读4分钟

文章

  1. Android文件管理器选择文件,获得文件路径URI转File
  2. Android uri 转换文件路径
  3. Android 接收微信、QQ其他应用打开,第三方分享
  4. 与其他应用交互
  5. 从其他应用接收简单的数据
  6. android10以上 uri转file uri转真实路径
  7. Android中Uri和path file三者的相互转换
  8. How to get the Full file path from URI | Newbedev
  9. Get File Path From URI in Android JAVA - Handy Opinion
  10. 检索文件信息  |  Android 开发者  |  Android Developers
  11. android - Get filename and path from URI from mediastore - Stack Overflow

验证

1. 通过Uri -> FileDescriptor -> FileInputStream -> FileChannel

实在是想获取别的进程用FileProvider传过来的Uri对应的路径,
那就通过int fd = getContentResolver().openFileDescriptor().getFd()方法获取文件描述符,
然后获取/proc/{pid}/fd/{fd}文件的getCanonicalPath(),
或者是native中用readklink()方法,可以拿到Uri对应文件的绝对路径
java\io\FileInputStream.java
public FileChannel getChannel() {
    synchronized (this) {
        if (channel == null) {
            channel = FileChannelImpl.open(fd, path, true, false, this);
        }
        return channel;
    }
}
try {
    var f1: File = File(it.path)
    var f2: File = File(it.toString())
    LogUtils.d(TagConstants.URI_TO_FILE, "f1 correct:" + f1.exists() + " ; f2 correct:" + f2.exists())
    LogUtils.d(TagConstants.URI_TO_FILE, "f1 correct:" + f1.absolutePath + " ; f2 correct:" + f2.absolutePath)
} catch (e: Exception) {
    LogUtils.d(TagConstants.URI_TO_FILE, "gain file error. err:" + e.message)
}
try {
    LogUtils.d(TagConstants.URI_TO_FILE, "gain fd.");
    var fd: FileDescriptor? =  contentResolver.openFileDescriptor(it,"r")?.fileDescriptor
    var fi: FileInputStream? = null;
    if(fd != null){
        LogUtils.d(TagConstants.URI_TO_FILE, "gain fi.")
        fi = FileInputStream(fd)
        LogUtils.d(TagConstants.URI_TO_FILE, "gain fc.")
        var fc:FileChannel =  fi.channel
        if(fc == null){
            LogUtils.d(TagConstants.URI_TO_FILE, "gain fc. fc is null.")
        }else{
            LogUtils.d(TagConstants.URI_TO_FILE, "gain fc. fc is not null.")
        }
    }else{
        LogUtils.d(TagConstants.URI_TO_FILE, "gain fc. fd is null.")
    }
} catch (e: Exception) {
    LogUtils.d(TagConstants.URI_TO_FILE, "gain fc. err:" + e.message)
    e.printStackTrace()
}

2021-09-16 01:14:08.324 15897-15897 D/TagUriToFile: f1 correct:false ; f2 correct:false
2021-09-16 01:14:08.324 15897-15897 D/TagUriToFile: f1 correct:/2/352 ; f2 correct:/content:/com.google.android.apps.nbu.files.provider/2/352
2021-09-16 01:14:08.324 15897-15897 D/TagUriToFile: gain fd.
2021-09-16 01:14:08.331 15897-15897 D/TagUriToFile: gain fi.
2021-09-16 01:14:08.331 15897-15897 D/TagUriToFile: gain fc.
2021-09-16 01:14:08.331 15897-15897 D/TagUriToFile: gain fc. fc is not null.
2021-09-16 01:14:08.347 15897-15897 D/TagUriToFile: f1 correct:false ; f2 correct:false
2021-09-16 01:14:08.347 15897-15897 D/TagUriToFile: f1 correct:/2/36 ; f2 correct:/content:/com.google.android.apps.nbu.files.provider/2/36
2021-09-16 01:14:08.347 15897-15897 D/TagUriToFile: gain fd.
2021-09-16 01:14:08.350 15897-15897 D/TagUriToFile: gain fi.
2021-09-16 01:14:08.350 15897-15897 D/TagUriToFile: gain fc.
2021-09-16 01:14:08.350 15897-15897 D/TagUriToFile: gain fc. fc is not null.
2021-09-16 01:14:08.363 15897-15897 D/TagUriToFile: f1 correct:false ; f2 correct:false
2021-09-16 01:14:08.363 15897-15897 D/TagUriToFile: f1 correct:/2/29 ; f2 correct:/content:/com.google.android.apps.nbu.files.provider/2/29
2021-09-16 01:14:08.363 15897-15897 D/TagUriToFile: gain fd.
2021-09-16 01:14:08.366 15897-15897 D/TagUriToFile: gain fi.
2021-09-16 01:14:08.366 15897-15897 D/TagUriToFile: gain fc.
2021-09-16 01:14:08.366 15897-15897 D/TagUriToFile: gain fc. fc is not null.
2021-09-16 01:14:08.378 15897-15897 D/TagUriToFile: f1 correct:false ; f2 correct:false
2021-09-16 01:14:08.379 15897-15897 D/TagUriToFile: f1 correct:/2/28 ; f2 correct:/content:/com.google.android.apps.nbu.files.provider/2/28
2021-09-16 01:14:08.379 15897-15897 D/TagUriToFile: gain fd.
2021-09-16 01:14:08.382 15897-15897 D/TagUriToFile: gain fi.
2021-09-16 01:14:08.383 15897-15897 D/TagUriToFile: gain fc.
2021-09-16 01:14:08.383 15897-15897 D/TagUriToFile: gain fc. fc is not null.

2. 验证直接通过Uri获取InputStream和Uri->FileDescriptor->FileInputStream,两者读取效率差异

  • 从log看两者读取效率无明显差异.
//1: 
// FileDescriptor fd = contentResolver.openFileDescriptor(uri,"r").getFileDescriptor();
// FileInputStream fi = new FileInputStream(fd);
2021-09-24 17:00:59.331 28244-28283 D/TagUriPath: getFileSize. FileInputStream.curr: 1048576
2021-09-24 17:01:08.795 28244-28283 D/TagUriPath: getFileSize. FileInputStream.curr: 7181312198
2021-09-24 17:01:08.796 28244-28283 D/TagUriPath: getFileSize. FileInputStream <= -1. break.

//2: testIs = context.getApplicationContext().getContentResolver().openInputStream(uri);
2021-09-24 17:03:31.378 28639-28639 D/TagUriPath: getFileSize. fileSize:7181312198
2021-09-24 17:03:31.388 28639-28639 D/TagUriPath: getFileSize. is.start. FileInputStream.total: 0
2021-09-24 17:03:42.381 28639-28639 D/TagUriPath: getFileSize. is.end. FileInputStream.total: 7181312198

从log上,可见读取7G左右的文件,直接使用InputStream和得到FileDescriptor再转FileInputStream,读取效率很接近.