Android--文件路径和Uri

本文介绍了Android中Uri的概念,以及如何在内部保存和相互转换Uri与文件路径。通过示例展示了如何从Uri获取文件路径,以及如何从文件路径得到Uri,特别提到了在处理不同来源的文件路径时可能遇到的问题。

一、Uri 

     通用资源标志符(Universal Resource Identifier, 简称"URI")。

  Uri代表要操作的数据,Android上可用的每种资源 - 图像、视频片段等都可以用Uri来表示。

  URI一般由三部分组成:

    访问资源的命名机制。 

    存放资源的主机名。 

    资源自身的名称,由路径表示。 

  Android的Uri由以下三部分组成: "content://"、数据的路径、标示ID(可选)

  举些例子,如: 

    所有联系人的Uri: content://contacts/people

    某个联系人的Uri: content://contacts/people/5

    所有图片Uri: content://media/external

    某个图片的Uri:content://media/external/images/media/4

二、内部保存

首先我们来看一下android是如何管理多媒体文件(音频、视频、图片)的信息。通过DDMS,我们在/data/data/com.android.providers.media下找到数据库文件

打开external.db文件进一步查看:在media表格下,可以看到文件路径(_data)和Uri的标示ID(_id)的对应关系。
            

三、相互转换

 1.从Uri获得文件路径

[java]  view plain copy print ?
  1. string  myImageUrl = "content://media/external/images/media/***";  
  2. Uri uri = Uri.parse(myImageUrl);  
  3.   
  4.   
  5. String[] proj = { MediaStore.Images.Media.DATA };     
  6. Cursor actualimagecursor = this.ctx.managedQuery(uri,proj,null,null,null);    
  7. int actual_image_column_index = actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);     
  8. actualimagecursor.moveToFirst();     
  9.   
  10.   
  11. String img_path = actualimagecursor.getString(actual_image_column_index);    
  12. File file = new File(img_path);  
  13. Uri fileUri = Uri.fromFile(file);  

 2、从文件路径获得Uri

[java]  view plain copy print ?
  1. Uri mUri = Uri.parse("content://media/external/images/media");   
  2. Uri mImageUri = null;  
  3.   
  4. Cursor cursor = managedQuery(  
  5.         MediaStore.Images.Media.EXTERNAL_CONTENT_URI, nullnull,  
  6.         null, MediaStore.Images.Media.DEFAULT_SORT_ORDER);  
  7. cursor.moveToFirst();  
  8.   
  9. while (!cursor.isAfterLast()) {  
  10.     String data = cursor.getString(cursor  
  11.             .getColumnIndex(MediaStore.MediaColumns.DATA));  
  12.     if (picPath.equals(data)) {  
  13.         int ringtoneID = cursor.getInt(cursor  
  14.                 .getColumnIndex(MediaStore.MediaColumns._ID));  
  15.         mImageUri = Uri.withAppendedPath(mUri, ""  
  16.                 + ringtoneID);  
  17.         break;  
  18.     }  
  19.     cursor.moveToNext();  
  20. }  

android 获取uri的正确文件路径的办法

有时会从其他的文件浏览器获取路径,这时根据路径去数据库取文件时会发现不成功,原因是由于android的文件浏览器太多,各自返回的路径不统一,而android本身的数据库中的路径是绝对路径,即"/mnt"开头的路径。

private String getRealPath(Uri fileUrl) {
		String fileName = null;
		Uri filePathUri = fileUrl;
		if (fileUrl != null) {
			if (fileUrl.getScheme().toString().compareTo("content") == 0) { // content://开头的uri
				Cursor cursor = context.getContentResolver().query(fileUrl,
						null, null, null, null);
				if (cursor != null && cursor.moveToFirst()) {
					int column_index = cursor
							.getColumnIndexOrThrow(MediaStore.Images.Thumbnails.DATA);
					fileName = cursor.getString(column_index); // 取出文件路径

					// if(!fileName.startsWith("/mnt")){
					// //检查是否有”/mnt“前缀
					// fileName = "/mnt" + fileName;
					// }

					cursor.close();
				}
			} else if (fileUrl.getScheme().compareTo("file") == 0) { // file:///开头的uri
				fileName = filePathUri.toString();
				fileName = filePathUri.toString().replace("file://", "");

				// 替换file://
				// if(!fileName.startsWith("/mnt")){
				// fileName = "/mnt" + fileName;
				// }
			}
		}
		if (fileName != null) {
			// 避免空指针
			try {
				fileName = new String(fileName.getBytes(), "utf-8");
				System.out.println("编码了!!!!!");
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
			// 编码含有中文路径
			fileName = URLDecoder.decode(fileName);
		}
		return fileName;
	}



Android 中,从 `Uri` 获取实际文件路径是一个常见的需求,尤其是在处理多媒体文件(如图片、音频、视频)时。然而,随着 Android 版本的演进,特别是在 Android 6.0(Marshmallow)及更高版本中,由于系统对文件访问权限的限制,传统的通过 `MediaStore` 查询文件路径的方法可能不再适用。 ### 从 Uri 获取文件路径的通用方法 以下是一个适用于 Android 6.0 叐版本的通用方法,能够从 `Uri` 获取文件的实际路径: ```java public String getRealPathFromUri(Uri uri, Context context) { String filePath = null; if (uri.getScheme().equals("content")) { try (Cursor cursor = context.getContentResolver().query(uri, new String[]{MediaStore.MediaColumns.DATA}, null, null, null)) { if (cursor != null && cursor.moveToFirst()) { int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA); filePath = cursor.getString(columnIndex); } } catch (Exception e) { e.printStackTrace(); } } else if (uri.getScheme().equals("file")) { filePath = uri.getPath(); } return filePath; } ``` ### 适配 Android 10 及更高版本 从 Android 10(API 级别 29)开始,系统引入了 **Scoped Storage**,进一步限制了直接访问文件路径的能力。在这种情况下,推荐使用 `ContentResolver` 或 `MediaStore` 来访问文件,而不是依赖于文件路径。例如: ```java public InputStream getInputStreamFromUri(Uri uri, Context context) throws IOException { return context.getContentResolver().openInputStream(uri); } ``` 通过 `InputStream`,可以直接读取文件内容,而不必获取其实际路径。如果确实需要文件路径,可以将文件内容复制到应用的私有目录中,并在该目录下操作文件。 ### 替代方案:使用 FileProvider 在某些场景下,例如分享文件给其他应用时,可以使用 `FileProvider` 来生成一个 `content://` 类型的 `Uri`,该 `Uri` 可以安全地传递给其他应用,而无需暴露实际文件路径: ```xml <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> ``` 在 `res/xml/file_paths.xml` 中定义可访问的文件路径: ```xml <?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_files" path="." /> </paths> ``` 然后通过 `FileProvider.getUriForFile()` 获取 `Uri`: ```java File file = new File(context.getExternalFilesDir(null), "example.txt"); Uri uri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", file); ``` ### 总结 -Android 6.0 及以上版本中,通过 `MediaStore` 查询文件路径可能不再适用,需使用 `ContentResolver` 查询文件路径- Android 10 及更高版本引入了 Scoped Storage,建议使用 `InputStream` 或 `FileProvider` 来处理文件访问。 - 对于跨应用文件共享,推荐使用 `FileProvider` 生成安全的 `content://` 类型 `Uri` [^1]。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值