> 文章列表 > Documentsui URI转为绝对路径

Documentsui URI转为绝对路径

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,已经在代码中复制到了指定路径,暂时无法解析出绝对路径。