在我的应用中,用户将选择应用随后处理的音频文件。问题是,为了让应用程序按照我想要的方式处理音频文件,我需要URI为文件格式。当我使用Android的原生音乐播放器浏览应用中的音频文件时,URI是一个内容URI,如下所示:
content://media/external/audio/media/710
但是,使用流行的文件管理器应用程序Astro,我得到以下结果:
file:///sdcard/media/audio/ringtones/GetupGetOut.mp3
后者对我来说更容易使用,但当然我希望应用程序具有用户选择的音频文件的功能,而不管他们用来浏览他们的集合的程序。所以我的问题是,有没有办法将content://
样式URI转换为file://
URI?否则,你会建议我解决这个问题?以下是调用选择器的代码,供参考:
Intent ringIntent = new Intent();
ringIntent.setType("audio/mp3");
ringIntent.setAction(Intent.ACTION_GET_CONTENT);
ringIntent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(Intent.createChooser(ringIntent, "Select Ringtone"), SELECT_RINGTONE);
我使用内容URI执行以下操作:
m_ringerPath = m_ringtoneUri.getPath();
File file = new File(m_ringerPath);
然后用所述文件做一些FileInputStream。
答案 0 :(得分:129)
只需使用getContentResolver().openInputStream(uri)
从URI中获取InputStream
。
答案 1 :(得分:40)
您可以使用内容解析程序从file://
URI获取content://
路径:
String filePath = null;
Uri _uri = data.getData();
Log.d("","URI = "+ _uri);
if (_uri != null && "content".equals(_uri.getScheme())) {
Cursor cursor = this.getContentResolver().query(_uri, new String[] { android.provider.MediaStore.Images.ImageColumns.DATA }, null, null, null);
cursor.moveToFirst();
filePath = cursor.getString(0);
cursor.close();
} else {
filePath = _uri.getPath();
}
Log.d("","Chosen path = "+ filePath);
答案 2 :(得分:7)
灵感的答案是Jason LaBrun和Darth Raven。尝试已经解决的方法使我找到了以下解决方案,该解决方案可能主要涵盖游标为空的情况以及从 content:// 到 file://
的转换要转换文件,请从获取的uri读写文件
public static Uri getFilePathFromUri(Uri uri) throws IOException {
String fileName = getFileName(uri);
File file = new File(myContext.getExternalCacheDir(), fileName);
file.createNewFile();
try (OutputStream outputStream = new FileOutputStream(file);
InputStream inputStream = myContext.getContentResolver().openInputStream(uri)) {
FileUtil.copyStream(inputStream, outputStream); //Simply reads input to output stream
outputStream.flush();
}
return Uri.fromFile(file);
}
要使用文件名,它将覆盖光标为空的大小写
public static String getFileName(Uri uri) {
String fileName = getFileNameFromCursor(uri);
if (fileName == null) {
String fileExtension = getFileExtension(uri);
fileName = "temp_file" + (fileExtension != null ? "." + fileExtension : "");
} else if (!fileName.contains(".")) {
String fileExtension = getFileExtension(uri);
fileName = fileName + "." + fileExtension;
}
return fileName;
}
从mime类型转换为文件扩展名是一个很好的选择
public static String getFileExtension(Uri uri) {
String fileType = myContext.getContentResolver().getType(uri);
return MimeTypeMap.getSingleton().getExtensionFromMimeType(fileType);
}
光标获取文件名
public static String getFileNameFromCursor(Uri uri) {
Cursor fileCursor = myContext.getContentResolver().query(uri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null);
String fileName = null;
if (fileCursor != null && fileCursor.moveToFirst()) {
int cIndex = fileCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
if (cIndex != -1) {
fileName = fileCursor.getString(cIndex);
}
}
return fileName;
}
答案 3 :(得分:6)
如果您的内容Uri为content://com.externalstorage...
,则可以使用此方法获取Android 19或更高版本上的文件夹或文件的绝对路径。
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
System.out.println("getPath() uri: " + uri.toString());
System.out.println("getPath() uri authority: " + uri.getAuthority());
System.out.println("getPath() uri path: " + uri.getPath());
// ExternalStorageProvider
if ("com.android.externalstorage.documents".equals(uri.getAuthority())) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
System.out.println("getPath() docId: " + docId + ", split: " + split.length + ", type: " + type);
// This is for checking Main Memory
if ("primary".equalsIgnoreCase(type)) {
if (split.length > 1) {
return Environment.getExternalStorageDirectory() + "/" + split[1] + "/";
} else {
return Environment.getExternalStorageDirectory() + "/";
}
// This is for checking SD Card
} else {
return "storage" + "/" + docId.replace(":", "/");
}
}
}
return null;
}
您可以检查Uri的每个部分是否正在使用println。下面列出了SD卡和设备主存储器的返回值。您可以访问和删除文件是否在内存中但我无法使用此方法从SD卡中删除文件,只能读取或打开 d使用此绝对路径的图像。如果您找到了使用此方法删除的解决方案,请分享。 SD卡
getPath() uri: content://com.android.externalstorage.documents/tree/612E-B7BF%3A/document/612E-B7BF%3A
getPath() uri authority: com.android.externalstorage.documents
getPath() uri path: /tree/612E-B7BF:/document/612E-B7BF:
getPath() docId: 612E-B7BF:, split: 1, type: 612E-B7BF
主记忆
getPath() uri: content://com.android.externalstorage.documents/tree/primary%3A/document/primary%3A
getPath() uri authority: com.android.externalstorage.documents
getPath() uri path: /tree/primary:/document/primary:
getPath() docId: primary:, split: 1, type: primary
如果您希望在获取路径后使用file:///
获取Uri
DocumentFile documentFile = DocumentFile.fromFile(new File(path));
documentFile.getUri() // will return a Uri with file Uri
答案 4 :(得分:5)
尝试通过调用ContentResolver.query()
来处理带有content:// scheme的URI不是一个好的解决方案。在运行4.2.2的HTC Desire上,您可以获得NULL作为查询结果。
为什么不使用ContentResolver呢? https://stackoverflow.com/a/29141800/3205334
答案 5 :(得分:1)
我回答有点迟,但我的代码已经过测试
从uri检查方案:
byte[] videoBytes;
if (uri.getScheme().equals("content")){
InputStream iStream = context.getContentResolver().openInputStream(uri);
videoBytes = getBytes(iStream);
}else{
File file = new File(uri.getPath());
FileInputStream fileInputStream = new FileInputStream(file);
videoBytes = getBytes(fileInputStream);
}
在上面的答案中,我将视频uri转换为字节数组,但这与问题无关,
我刚刚复制了我的完整代码,以显示FileInputStream
和InputStream
的用法,因为两者在我的代码中的工作方式相同。
我在片段中使用了变量上下文getActivity(),在Activity中它只是ActivityName.this
context=getActivity();
//在Fragment
context=ActivityName.this;
//在活动中
答案 6 :(得分:0)
尝试一下。...
从内容uri获取文件
fun fileFromContentUri(context: Context, contentUri: Uri): File {
// Preparing Temp file name
val fileExtension = getFileExtension(context, contentUri)
val fileName = "temp_file" + if (fileExtension != null) ".$fileExtension" else ""
// Creating Temp file
val tempFile = File(context.cacheDir, fileName)
tempFile.createNewFile()
try {
val oStream = FileOutputStream(tempFile)
val inputStream = context.contentResolver.openInputStream(contentUri)
inputStream?.let {
copy(inputStream, oStream)
}
oStream.flush()
} catch (e: Exception) {
e.printStackTrace()
}
return tempFile
}
private fun getFileExtension(context: Context, uri: Uri): String? {
val fileType: String? = context.contentResolver.getType(uri)
return MimeTypeMap.getSingleton().getExtensionFromMimeType(fileType)
}
@Throws(IOException::class)
private fun copy(source: InputStream, target: OutputStream) {
val buf = ByteArray(8192)
var length: Int
while (source.read(buf).also { length = it } > 0) {
target.write(buf, 0, length)
}
}
答案 7 :(得分:0)
您可以通过简单的方法通过uri获取文件名
fun get_filename_by_uri(uri : Uri) : String{
contentResolver.query(uri, null, null, null, null).use { cursor ->
cursor?.let {
val nameIndex = it.getColumnIndex(OpenableColumns.DISPLAY_NAME)
it.moveToFirst()
return it.getString(nameIndex)
}
}
return ""
}
并且易于使用
阅读contentResolver.openInputStream(uri)
答案 8 :(得分:0)
您可以使用此功能在新的 android 中从 uri 获取文件
fun getFileFromUri(uri: Uri): File? {
if (uri.path == null) {
return null
}
var realPath = String()
val databaseUri: Uri
val selection: String?
val selectionArgs: Array<String>?
if (uri.path!!.contains("/document/image:")) {
databaseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
selection = "_id=?"
selectionArgs = arrayOf(DocumentsContract.getDocumentId(uri).split(":")[1])
} else {
databaseUri = uri
selection = null
selectionArgs = null
}
try {
val column = "_data"
val projection = arrayOf(column)
val cursor = context.contentResolver.query(
databaseUri,
projection,
selection,
selectionArgs,
null
)
cursor?.let {
if (it.moveToFirst()) {
val columnIndex = cursor.getColumnIndexOrThrow(column)
realPath = cursor.getString(columnIndex)
}
cursor.close()
}
} catch (e: Exception) {
Log.i("GetFileUri Exception:", e.message ?: "")
}
val path = if (realPath.isNotEmpty()) realPath else {
when {
uri.path!!.contains("/document/raw:") -> uri.path!!.replace(
"/document/raw:",
""
)
uri.path!!.contains("/document/primary:") -> uri.path!!.replace(
"/document/primary:",
"/storage/emulated/0/"
)
else -> return null
}
}
return File(path)
}