什么是最简单的方法从android.net.Uri对象持有一个文件:类型转换为java.io.File对象在Android?

我尝试了下面的方法,但不管用:

File file = new File(Environment.getExternalStorageDirectory(), "read.me");
Uri uri = Uri.fromFile(file);
File auxFile = new File(uri.toString());
assertEquals(file.getAbsolutePath(), auxFile.getAbsolutePath());

当前回答

uri.toString()给我:"content://com.google.android.apps.nbu.files.provider/1/file%3A%2F%2F%2Fstorage%2Femulated%2F0%2FDownload%2Fbackup.file"

uri.getPath()给我:“/1/文件:///存储/模拟/0/下载/备份文件。”

new File(uri.getPath())给我“/1/ File:/storage/ emululated /0/Download/backup.file”。

所以如果你有一个文件的访问权限,想要避免使用ContentResolver或直接读取文件,答案是:

private String uriToPath( Uri uri )
{
    File backupFile = new File( uri.getPath() );
    String absolutePath = backupFile.getAbsolutePath();
    return absolutePath.substring( absolutePath.indexOf( ':' ) + 1 );
}

为简化回答,跳过错误处理

其他回答

文件imageToUpload =新文件(新URI(androidURI.toString()));如果这是你在外部存储中创建的文件,则有效。

例如file:///storage/emulated/0/(一些目录和文件名)

这些对我都没用。我发现这是可行的解决方案。但我的情况仅限于图像。

String[] filePathColumn = { MediaStore.Images.Media.DATA };
Cursor cursor = getActivity().getContentResolver().query(uri, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String filePath = cursor.getString(columnIndex);
cursor.close();

你想要的是…

new File(uri.getPath());

... ,而不是……

new File(uri.toString());

笔记

对于android.net.Uri对象,它被命名为uri并完全按照问题中创建,uri. tostring()返回一个“file:///mnt/sdcard/myPicture.jpg”格式的字符串,而uri. getpath()返回一个“/mnt/sdcard/myPicture.jpg”格式的字符串。 我知道在Android系统中文件存储有一些细微差别。在这个回答中,我的意图是准确地回答提问者所问的问题,而不是深究其中的细微差别。

扩展基于@Jacek kwiecievik回答转换图像uri文件

fun Uri.toImageFile(context: Context): File? {
    val filePathColumn = arrayOf(MediaStore.Images.Media.DATA)
    val cursor = context.contentResolver.query(this, filePathColumn, null, null, null)
    if (cursor != null) {
        if (cursor.moveToFirst()) {
            val columnIndex = cursor.getColumnIndex(filePathColumn[0])
            val filePath = cursor.getString(columnIndex)
            cursor.close()
            return File(filePath)
        }
        cursor.close()
    }
    return null
}

如果我们使用File(uri.getPath()),它将不起作用

如果我们使用扩展从android-ktx,它仍然不能工作,因为 https://github.com/android/android-ktx/blob/master/src/main/java/androidx/core/net/Uri.kt

一些库需要文件对象的过程,如改造,一些图像编辑器等。 将URI转换为文件对象或任何类似的东西,我们有一种方法,这是支持所有android旧版本和即将到来的版本。

步骤1:

你必须在FilesDir中创建一个新文件,这个文件对于其他与我们的文件和扩展名相同的应用程序是不可读的。

步骤2:

您必须通过使用InputStream复制URI的内容来创建一个文件。

File f = getFile(getApplicationContext(), uri);

public static File getFile(Context context, Uri uri) throws IOException {
    File destinationFilename = new File(context.getFilesDir().getPath() + File.separatorChar + queryName(context, uri));
    try (InputStream ins = context.getContentResolver().openInputStream(uri)) {
        createFileFromStream(ins, destinationFilename);
    } catch (Exception ex) {
        Log.e("Save File", ex.getMessage());
        ex.printStackTrace();
    }
    return destinationFilename;
}

public static void createFileFromStream(InputStream ins, File destination) {
    try (OutputStream os = new FileOutputStream(destination)) {
        byte[] buffer = new byte[4096];
        int length;
        while ((length = ins.read(buffer)) > 0) {
            os.write(buffer, 0, length);
        }
        os.flush();
    } catch (Exception ex) {
        Log.e("Save File", ex.getMessage());
        ex.printStackTrace();
    }
}

private static String queryName(Context context, Uri uri) {
    Cursor returnCursor =
            context.getContentResolver().query(uri, null, null, null, null);
    assert returnCursor != null;
    int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
    returnCursor.moveToFirst();
    String name = returnCursor.getString(nameIndex);
    returnCursor.close();
    return name;
}