Documentsui URI转为绝对路径

背景

有个OTA本地升级功能需要将本地的ota升级包复制到/data/ota_package目录下,然后通过data/ota_package/update.zip文件进行升级,打算通过启动DocumentsUI让用户选择保存在本地的升级包。

分析

通过以下代码启动documentsui

private void pickLocalFileToUpgrade() {
	Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
	intent.setType("*/*");
	startActivityForResult(intent, REQUEST_CODE_FILE);
}

当用户选择在DocumentsUI中选择了文件后,我们可以通过如下方法进行获取:

@Override
protectedvoid onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
	if (data == null) {
		Log.e(TAG, "do not select any file!!!");
		return;
	}
	Log.d(TAG, "selected file info: " + data.toString());
	if (requestCode == REQUEST_CODE_FILE) {
		Uri uri = data.getData();
	}
	super.onActivityResult(requestCode, resultCode, data);
}

上述方法只能获取到文件的URI地址,如果我们要把文件复制到/data/ota_package目录下,需要获取到源文件的绝对地址,然后通过File 类加载并复制。
同时,不同的时候选择文件后返回的类型可能不一样:

  • 使用adb push文件到sdcard/Download目录下,此时选择文件,得到的URI为"content://com.android.providers.downloads.documents/document/raw:/storage/emulated/0/Download/update.zip"
  • 重启过后在此选择,得到的URI为"content://com.android.providers.downloads.documents/document/msf:180"
  • 通过internal storage 选择后,得到的URI为"content://com.android.externalstorage.documents/document/primary:Download/update.zip"

解决方法

针对第一类,直接截取字符串即为文件的绝对路径

public String getPath(Uri uri){
	final String id = DocumentsContract.getDocumentId(uri);
	if(id.startsWith("raw:")) {
    	return id.substring(4);
    }
}

针对第二类,需要使用其他方法进行处理,通过context.getContentResolver().openInputStream(uri) 加载uri对应的文件,再通过IO流写到对应的文件位置

// destinationPath 为需要复制到目的地址
public static void saveFileFromUri(Context context, Uri uri, String destinationPath) {
        InputStream is = null;
        BufferedOutputStream bos = null;
        try {
            is = context.getContentResolver().openInputStream(uri);
            bos = new BufferedOutputStream(new FileOutputStream(destinationPath, false));
            byte[] buf = new byte[1024];
            int bytesRead = 0;
            while (-1 != (bytesRead = is.read(buf, 0, buf.length))) {
                bos.write(buf,0,bytesRead);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) is.close();
                if (bos != null) bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

针对第三类,获取方法如下

public String getPath(Uri uri){
	final String id = DocumentsContract.getDocumentId(uri);
	final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),
                            Long.valueOf(id));
    path = getDataColumn(context, contentUri, null, null);
}

private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
    Cursor cursor = null;
    final String column = "_data";
    final String[] projection = {column};
    try {
        cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
        if (cursor != null && cursor.moveToFirst()) {
            final int column_index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(column_index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }
    return null;
}

至此,第一、三类已经把DocumentUI里download目录下的URI全部转为了绝对地址,如果需要复制到指定路径,可以通过以下方法实现:

public static void copyFile(File sourceFile, File destFile) {
    Log.d(TAG, "copyFile to " + destFile.toPath());
    try {
        Files.copy(sourceFile.toPath(),destFile.toPath());
    } catch (IOException e) {
        e.printStackTrace();
    }
}

关于第二类URI,已经在代码中复制到了指定路径,暂时无法解析出绝对路径。

你可能感兴趣的:(android,documentsui,uri,uri转绝对路径)