从媒体存储中的 URI 获取文件名和路径
-
25-09-2019 - |
题
我有一个 onActivityResult
从媒体存储图像选择返回,我可以使用以下命令获取图像的 URI:
Uri selectedImage = data.getData();
将其转换为字符串给出:
content://media/external/images/media/47
或者路径给出:
/external/images/media/47
然而,我似乎找不到一种方法将其转换为绝对路径,因为我想将图像加载到位图中,而不必将其复制到某个地方。我知道这可以使用 URI 和内容解析器来完成,但我猜这似乎会在重新启动手机时中断 MediaStore
在重新启动之间不会保持其编号相同。
解决方案
下面API 19 使用此代码从URI获取文件路径:
public String getRealPathFromURI(Context context, Uri contentUri) {
Cursor cursor = null;
try {
String[] proj = { MediaStore.Images.Media.DATA };
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
其他提示
只是对第一个答案的简单更新: mActivity.managedQuery()
现已弃用。我已经用新方法更新了代码。
private String getRealPathFromURI(Uri contentUri) {
String[] proj = { MediaStore.Images.Media.DATA };
CursorLoader loader = new CursorLoader(mContext, contentUri, proj, null, null, null);
Cursor cursor = loader.loadInBackground();
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String result = cursor.getString(column_index);
cursor.close();
return result;
}
有关奥利奥
Uri uri = data.getData();
File file = new File(uri.getPath());//create path from uri
final String[] split = file.getPath().split(":");//split the path.
filePath = split[1];//assign it to a string(your choice).
有关以下奥利奥我所有版本都取得此方法,该方法得到的URI
真实路径 @SuppressLint("NewApi")
public static String getFilePath(Context context, Uri uri) throws URISyntaxException {
String selection = null;
String[] selectionArgs = null;
// Uri is different in versions after KITKAT (Android 4.4), we need to
if (Build.VERSION.SDK_INT >= 19 && DocumentsContract.isDocumentUri(context.getApplicationContext(), uri)) {
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
return Environment.getExternalStorageDirectory() + "/" + split[1];
} else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
uri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
} else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("image".equals(type)) {
uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
selection = "_id=?";
selectionArgs = new String[]{
split[1]
};
}
}
if ("content".equalsIgnoreCase(uri.getScheme())) {
if (isGooglePhotosUri(uri)) {
return uri.getLastPathSegment();
}
String[] projection = {
MediaStore.Images.Media.DATA
};
Cursor cursor = null;
try {
cursor = context.getContentResolver()
.query(uri, projection, selection, selectionArgs, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
if (cursor.moveToFirst()) {
return cursor.getString(column_index);
}
} catch (Exception e) {
e.printStackTrace();
}
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
不要试图找到在文件系统中的URI,这是缓慢的去看看东西在数据库中。
您可以通过像你给一个文件到工厂给的输入流工厂得到一个URI位图:
InputStream is = getContentResolver().openInputStream(uri);
Bitmap bitmap = BitmapFactory.decodeStream(is);
is.close();
这是我得到的文件名,从URI像文件的例子:// ...和内容:// ...。这不仅与Android MediaStore也与像EzExplorer第三方应用程序的工作对我来说。
public static String getFileNameByUri(Context context, Uri uri)
{
String fileName="unknown";//default fileName
Uri filePathUri = uri;
if (uri.getScheme().toString().compareTo("content")==0)
{
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
if (cursor.moveToFirst())
{
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);//Instead of "MediaStore.Images.Media.DATA" can be used "_data"
filePathUri = Uri.parse(cursor.getString(column_index));
fileName = filePathUri.getLastPathSegment().toString();
}
}
else if (uri.getScheme().compareTo("file")==0)
{
fileName = filePathUri.getLastPathSegment().toString();
}
else
{
fileName = fileName+"_"+filePathUri.getLastPathSegment();
}
return fileName;
}
好现有的答案,其中一些我曾经拿出我自己的:
我不得不从路径得到的URI路径,并获得URI,而谷歌也很难告诉区别所以对于任何人谁具有同样的问题(例如,从视频的MediaStore
其物理拿到缩略图位置你已经有了)。前者:
/**
* Gets the corresponding path to a file from the given content:// URI
* @param selectedVideoUri The content:// URI to find the file path from
* @param contentResolver The content resolver to use to perform the query.
* @return the file path as a string
*/
private String getFilePathFromContentUri(Uri selectedVideoUri,
ContentResolver contentResolver) {
String filePath;
String[] filePathColumn = {MediaColumns.DATA};
Cursor cursor = contentResolver.query(selectedVideoUri, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
filePath = cursor.getString(columnIndex);
cursor.close();
return filePath;
}
后者(我为视频做的,但也可通过替代MediaStore.Audio(等)用于MediaStore.Video用于音频或文件或其他类型的存储的内容的):
/**
* Gets the MediaStore video ID of a given file on external storage
* @param filePath The path (on external storage) of the file to resolve the ID of
* @param contentResolver The content resolver to use to perform the query.
* @return the video ID as a long
*/
private long getVideoIdFromFilePath(String filePath,
ContentResolver contentResolver) {
long videoId;
Log.d(TAG,"Loading file " + filePath);
// This returns us content://media/external/videos/media (or something like that)
// I pass in "external" because that's the MediaStore's name for the external
// storage on my device (the other possibility is "internal")
Uri videosUri = MediaStore.Video.Media.getContentUri("external");
Log.d(TAG,"videosUri = " + videosUri.toString());
String[] projection = {MediaStore.Video.VideoColumns._ID};
// TODO This will break if we have no matching item in the MediaStore.
Cursor cursor = contentResolver.query(videosUri, projection, MediaStore.Video.VideoColumns.DATA + " LIKE ?", new String[] { filePath }, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(projection[0]);
videoId = cursor.getLong(columnIndex);
Log.d(TAG,"Video ID is " + videoId);
cursor.close();
return videoId;
}
基本上,DATA
的MediaStore
列(或任何它的子部分要查询)存储的文件路径,让你无论是使用你知道什么来查找DATA
场,或使用字段查找什么其他你想要的。
我然后进一步使用Scheme
如上找出与我的数据做:
private boolean getSelectedVideo(Intent imageReturnedIntent, boolean fromData) {
Uri selectedVideoUri;
//Selected image returned from another activity
// A parameter I pass myself to know whether or not I'm being "shared via" or
// whether I'm working internally to my app (fromData = working internally)
if(fromData){
selectedVideoUri = imageReturnedIntent.getData();
} else {
//Selected image returned from SEND intent
// which I register to receive in my manifest
// (so people can "share via" my app)
selectedVideoUri = (Uri)getIntent().getExtras().get(Intent.EXTRA_STREAM);
}
Log.d(TAG,"SelectedVideoUri = " + selectedVideoUri);
String filePath;
String scheme = selectedVideoUri.getScheme();
ContentResolver contentResolver = getContentResolver();
long videoId;
// If we are sent file://something or content://org.openintents.filemanager/mimetype/something...
if(scheme.equals("file") || (scheme.equals("content") && selectedVideoUri.getEncodedAuthority().equals("org.openintents.filemanager"))){
// Get the path
filePath = selectedVideoUri.getPath();
// Trim the path if necessary
// openintents filemanager returns content://org.openintents.filemanager/mimetype//mnt/sdcard/xxxx.mp4
if(filePath.startsWith("/mimetype/")){
String trimmedFilePath = filePath.substring("/mimetype/".length());
filePath = trimmedFilePath.substring(trimmedFilePath.indexOf("/"));
}
// Get the video ID from the path
videoId = getVideoIdFromFilePath(filePath, contentResolver);
} else if(scheme.equals("content")){
// If we are given another content:// URI, look it up in the media provider
videoId = Long.valueOf(selectedVideoUri.getLastPathSegment());
filePath = getFilePathFromContentUri(selectedVideoUri, contentResolver);
} else {
Log.d(TAG,"Failed to load URI " + selectedVideoUri.toString());
return false;
}
return true;
}
以上答案都不在所有情况下为我工作。我只好直接去谷歌的文档 https://developer.android.com/guide/topics/提供商/文档provider.html 关于此主题,发现这个有用的方法:
private Bitmap getBitmapFromUri(Uri uri) throws IOException {
ParcelFileDescriptor parcelFileDescriptor =
getContentResolver().openFileDescriptor(uri, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close();
return image;
}
可以使用该位图中的图像视图中显示它。
尝试从乌里
这个GET映像文件的路径public void getImageFilePath(Context context, Uri uri) {
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
cursor.moveToFirst();
String image_id = cursor.getString(0);
image_id = image_id.substring(image_id.lastIndexOf(":") + 1);
cursor.close();
cursor = context.getContentResolver().query(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, MediaStore.Images.Media._ID + " = ? ", new String[]{image_id}, null);
cursor.moveToFirst();
String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
cursor.close();
upLoadImageOrLogo(path);
}
<强> API 19和上述强>,图片文件路径从开放的强>完美地工作。我还要检查这个最新的 PIE API 28 。
public String getImageFilePath(Uri uri) {
String path = null, image_id = null;
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
image_id = cursor.getString(0);
image_id = image_id.substring(image_id.lastIndexOf(":") + 1);
cursor.close();
}
Cursor cursor = getContentResolver().query(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, MediaStore.Images.Media._ID + " = ? ", new String[]{image_id}, null);
if (cursor!=null) {
cursor.moveToFirst();
path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
cursor.close();
}
return path;
}
解那些,谁拥有移动到奇巧之后问题:
“这将让来自MediaProvider,DownloadsProvider和ExternalStorageProvider文件路径,而回落至非官方的ContentProvider方法” 的https: //stackoverflow.com/a/20559175/690777
从图库中获取图像后,只需在以下方法中传递 URI 即可 安卓4.4 (奇巧):
public String getPath(Uri contentUri) {// Will return "image:x*"
String wholeID = DocumentsContract.getDocumentId(contentUri);
// Split at colon, use second item in the array
String id = wholeID.split(":")[1];
String[] column = { MediaStore.Images.Media.DATA };
// Where id is equal to
String sel = MediaStore.Images.Media._ID + "=?";
Cursor cursor = getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, column, sel,
new String[] { id }, null);
String filePath = "";
int columnIndex = cursor.getColumnIndex(column[0]);
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex);
}
cursor.close();
return filePath;
}
由于managedQuery已被弃用,你可以尝试:
CursorLoader cursorLoader = new CursorLoader(context, uri, proj, null, null, null);
Cursor cursor = cursorLoader.loadInBackground();
在这里,我要告诉你的是如何创建一个浏览按钮,这时候你会点击,这将打开SD卡,您将选择一个文件,因此你会得到的文件名和文件路径所选择的一个的:
A按钮你将击中
browse.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
Intent intent = new Intent();
intent.setAction(Intent.ACTION_PICK);
Uri startDir = Uri.fromFile(new File("/sdcard"));
startActivityForResult(intent, PICK_REQUEST_CODE);
}
});
这将让所得到的文件名和文件路径
功能protected void onActivityResult(int requestCode, int resultCode, Intent intent)
{
if (requestCode == PICK_REQUEST_CODE)
{
if (resultCode == RESULT_OK)
{
Uri uri = intent.getData();
if (uri.getScheme().toString().compareTo("content")==0)
{
Cursor cursor =getContentResolver().query(uri, null, null, null, null);
if (cursor.moveToFirst())
{
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);//Instead of "MediaStore.Images.Media.DATA" can be used "_data"
Uri filePathUri = Uri.parse(cursor.getString(column_index));
String file_name = filePathUri.getLastPathSegment().toString();
String file_path=filePathUri.getPath();
Toast.makeText(this,"File Name & PATH are:"+file_name+"\n"+file_path, Toast.LENGTH_LONG).show();
}
}
}
}
}
此解决方案适用于所有情况下:
在某些情况下,您可以通过URL路径是太难了。那么为什么你需要的路径?要复制在其他地方的文件?你并不需要的路径。
public void SavePhotoUri (Uri imageuri, String Filename){
File FilePath = context.getDir(Environment.DIRECTORY_PICTURES,Context.MODE_PRIVATE);
try {
Bitmap selectedImage = MediaStore.Images.Media.getBitmap(context.getContentResolver(), imageuri);
String destinationImagePath = FilePath + "/" + Filename;
FileOutputStream destination = new FileOutputStream(destinationImagePath);
selectedImage.compress(Bitmap.CompressFormat.JPEG, 100, destination);
destination.close();
}
catch (Exception e) {
Log.e("error", e.toString());
}
}
尝试这个
不过,如果您遇到问题以获得真正的路径,您可以尝试我的答案。上面的答案对我没有帮助。
解释:- 此方法获取 URI,然后检查 Android 设备的 API 级别,然后根据 API 级别生成真实路径。 根据API级别不同,生成真实路径方法的代码也不同。
从 URI 获取真实路径的方法
@SuppressLint("ObsoleteSdkInt") public String getPathFromURI(Uri uri){ String realPath=""; // SDK < API11 if (Build.VERSION.SDK_INT < 11) { String[] proj = { MediaStore.Images.Media.DATA }; @SuppressLint("Recycle") Cursor cursor = getContentResolver().query(uri, proj, null, null, null); int column_index = 0; String result=""; if (cursor != null) { column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); realPath=cursor.getString(column_index); } } // SDK >= 11 && SDK < 19 else if (Build.VERSION.SDK_INT < 19){ String[] proj = { MediaStore.Images.Media.DATA }; CursorLoader cursorLoader = new CursorLoader(this, uri, proj, null, null, null); Cursor cursor = cursorLoader.loadInBackground(); if(cursor != null){ int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); realPath = cursor.getString(column_index); } } // SDK > 19 (Android 4.4) else{ String wholeID = DocumentsContract.getDocumentId(uri); // Split at colon, use second item in the array String id = wholeID.split(":")[1]; String[] column = { MediaStore.Images.Media.DATA }; // where id is equal to String sel = MediaStore.Images.Media._ID + "=?"; Cursor cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, column, sel, new String[]{ id }, null); int columnIndex = 0; if (cursor != null) { columnIndex = cursor.getColumnIndex(column[0]); if (cursor.moveToFirst()) { realPath = cursor.getString(columnIndex); } cursor.close(); } } return realPath; }
像这样使用这个方法
Log.e(TAG, "getRealPathFromURI: "+getPathFromURI(your_selected_uri) );
输出:-
04-06 12:39:46.993 6138-6138/com.app.qtm E/标签:从 URI 获取真实路径:/storage/emulated/0/Video/avengers_infinity_war_4k_8k-7680x4320.jpg
我做这样的:
Uri queryUri = MediaStore.Files.getContentUri("external");
String columnData = MediaStore.Files.FileColumns.DATA;
String columnSize = MediaStore.Files.FileColumns.SIZE;
String[] projectionData = {MediaStore.Files.FileColumns.DATA};
String name = null;
String size = null;
Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
if ((cursor != null)&&(cursor.getCount()>0)) {
int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
cursor.moveToFirst();
name = cursor.getString(nameIndex);
size = cursor.getString(sizeIndex);
cursor.close();
}
if ((name!=null)&&(size!=null)){
String selectionNS = columnData + " LIKE '%" + name + "' AND " +columnSize + "='" + size +"'";
Cursor cursorLike = getContentResolver().query(queryUri, projectionData, selectionNS, null, null);
if ((cursorLike != null)&&(cursorLike.getCount()>0)) {
cursorLike.moveToFirst();
int indexData = cursorLike.getColumnIndex(columnData);
if (cursorLike.getString(indexData) != null) {
result = cursorLike.getString(indexData);
}
cursorLike.close();
}
}
return result;
@PercyPercy的稍作修改的版本 - 它不会抛出,只是返回null如果出现任何错误
public String getPathFromMediaUri(Context context, Uri uri) {
String result = null;
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);
int col = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
if (col >= 0 && cursor.moveToFirst())
result = cursor.getString(col);
cursor.close();
return result;
}
在这里,你得到的文件
的名称String[] projection = {MediaStore.MediaColumns.DISPLAY_NAME};
Uri uri = data.getData();
String fileName = null;
ContentResolver cr = getActivity().getApplicationContext().getContentResolver();
Cursor metaCursor = cr.query(uri,
projection, null, null, null);
if (metaCursor != null) {
try {
if (metaCursor.moveToFirst()) {
fileName = metaCursor.getString(0);
}
} finally {
metaCursor.close();
}
}
简单和容易。您可以从URI做到这一点,就像下面!
public void getContents(Uri uri)
{
Cursor vidCursor = getActivity.getContentResolver().query(uri, null, null,
null, null);
if (vidCursor.moveToFirst())
{
int column_index =
vidCursor .getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
Uri filePathUri = Uri.parse(vidCursor .getString(column_index));
String video_name = filePathUri.getLastPathSegment().toString();
String file_path=filePathUri.getPath();
Log.i("TAG", video_name + "\b" file_path);
}
}
有关张贴任何方式的 Android Q的后,当MediaStore.Images.Media.DATA将不再提供?此字段在Android Q的折旧:
这个常数在API级别29弃用。 应用程序可能没有文件系统权限直接访问此路径。而不是试图直接打开这个路径,应用程序应该使用ContentResolver的#openFileDescriptor(URI,字符串)来访问。
https://developer.android.com/reference /android/provider/MediaStore.MediaColumns.html#DATA
完美工作对我来说从固定码本帖子:
public static String getRealPathImageFromUri(Uri uri) {
String fileName =null;
if (uri.getScheme().equals("content")) {
try (Cursor cursor = MyApplication.getInstance().getContentResolver().query(uri, null, null, null, null)) {
if (cursor.moveToFirst()) {
fileName = cursor.getString(cursor.getColumnIndexOrThrow(ediaStore.Images.Media.DATA));
}
} catch (IllegalArgumentException e) {
Log.e(mTag, "Get path failed", e);
}
}
return fileName;
}
作为一个附加的,如果你需要看到,如果你试图打开一个输入流前的文件存在,你可以使用DocumentsContract。
(科特林代码)
var iStream = null
if(DocumentsContract.isDocumentUri(context,myUri)) {
val pfd: ParcelFileDescriptor? = context.contentResolver.openFileDescriptor(
myUri, "r") ?: return null
iStream = ParcelFileDescriptor.AutoCloseInputStream(pfd)
}
由于上述答案没有工作对我来说,这里是解决方案,为我工作:
:用于既> 19和<= 19 API级别强>
本方法涵盖了所有的情况下,从URI
获得文件路径/**
* Get a file path from a Uri. This will get the the path for Storage Access
* Framework Documents, as well as the _data field for the MediaStore and
* other file-based ContentProviders.
*
* @param context The activity.
* @param uri The Uri to query.
* @author paulburke
*/
public static String getPath(final Context context, final Uri uri) {
// DocumentProvider
if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}else{
Toast.makeText(context, "Could not get file path. Please try again", Toast.LENGTH_SHORT).show();
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
} else {
contentUri = MediaStore.Files.getContentUri("external");
}
final String selection = "_id=?";
final String[] selectionArgs = new String[] {
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
要得到任何类型的文件路径使用这个的:
/*
* Copyright (C) 2007-2008 OpenIntents.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yourpackage;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.util.Log;
import android.webkit.MimeTypeMap;
import java.io.File;
import java.io.FileFilter;
import java.text.DecimalFormat;
import java.util.Comparator;
import java.util.List;
/**
* @author Peli
* @author paulburke (ipaulpro)
* @version 2013-12-11
*/
public class FileUtils {
private FileUtils() {
} //private constructor to enforce Singleton pattern
/**
* TAG for log messages.
*/
static final String TAG = "FileUtils";
private static final boolean DEBUG = true; // Set to true to enable logging
public static final String MIME_TYPE_AUDIO = "audio/*";
public static final String MIME_TYPE_TEXT = "text/*";
public static final String MIME_TYPE_IMAGE = "image/*";
public static final String MIME_TYPE_VIDEO = "video/*";
public static final String MIME_TYPE_APP = "application/*";
public static final String HIDDEN_PREFIX = ".";
/**
* Gets the extension of a file name, like ".png" or ".jpg".
*
* @param uri
* @return Extension including the dot("."); "" if there is no extension;
* null if uri was null.
*/
public static String getExtension(String uri) {
if (uri == null) {
return null;
}
int dot = uri.lastIndexOf(".");
if (dot >= 0) {
return uri.substring(dot);
} else {
// No extension.
return "";
}
}
/**
* @return Whether the URI is a local one.
*/
public static boolean isLocal(String url) {
if (url != null && !url.startsWith("http://") && !url.startsWith("https://")) {
return true;
}
return false;
}
/**
* @return True if Uri is a MediaStore Uri.
* @author paulburke
*/
public static boolean isMediaUri(Uri uri) {
return "media".equalsIgnoreCase(uri.getAuthority());
}
/**
* Convert File into Uri.
*
* @param file
* @return uri
*/
public static Uri getUri(File file) {
if (file != null) {
return Uri.fromFile(file);
}
return null;
}
/**
* Returns the path only (without file name).
*
* @param file
* @return
*/
public static File getPathWithoutFilename(File file) {
if (file != null) {
if (file.isDirectory()) {
// no file to be split off. Return everything
return file;
} else {
String filename = file.getName();
String filepath = file.getAbsolutePath();
// Construct path without file name.
String pathwithoutname = filepath.substring(0,
filepath.length() - filename.length());
if (pathwithoutname.endsWith("/")) {
pathwithoutname = pathwithoutname.substring(0, pathwithoutname.length() - 1);
}
return new File(pathwithoutname);
}
}
return null;
}
/**
* @return The MIME type for the given file.
*/
public static String getMimeType(File file) {
String extension = getExtension(file.getName());
if (extension.length() > 0)
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.substring(1));
return "application/octet-stream";
}
/**
* @return The MIME type for the give Uri.
*/
public static String getMimeType(Context context, Uri uri) {
File file = new File(getPath(context, uri));
return getMimeType(file);
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is {@link LocalStorageProvider}.
* @author paulburke
*/
public static boolean isLocalStorageDocument(Uri uri) {
return LocalStorageProvider.AUTHORITY.equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
* @author paulburke
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
* @author paulburke
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
* @author paulburke
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
* @author paulburke
*/
public 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()) {
if (DEBUG)
DatabaseUtils.dumpCursor(cursor);
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
}catch (Exception e){
e.printStackTrace();
}finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* Get a file path from a Uri. This will quickGet the the path for Storage Access
* Framework Documents, as well as the _data field for the MediaStore and
* other file-based ContentProviders.<br>
* <br>
* Callers should check whether the path is local before assuming it
* represents a local file.
*
* @param context The context.
* @param uri The Uri to query.
* @author paulburke
* @see #isLocal(String)
* @see #getFile(Context, Uri)
*/
public static String getPath(final Context context, final Uri uri) {
if (DEBUG)
Log.d(TAG + " File -",
"Authority: " + uri.getAuthority() +
", Fragment: " + uri.getFragment() +
", Port: " + uri.getPort() +
", Query: " + uri.getQuery() +
", Scheme: " + uri.getScheme() +
", Host: " + uri.getHost() +
", Segments: " + uri.getPathSegments().toString()
);
// DocumentProvider
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri)) {
// LocalStorageProvider
if (isLocalStorageDocument(uri)) {
// The path is the id
return DocumentsContract.getDocumentId(uri);
}
// ExternalStorageProvider
else if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
// if ("primary".equalsIgnoreCase(type)) {
// return Environment.getExternalStorageDirectory() + "/" + split[1];
// }
return Environment.getExternalStorageDirectory() + "/" + split[1];
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
try {
final String id = DocumentsContract.getDocumentId(uri);
Log.d(TAG, "getPath: id= " + id);
final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}catch (Exception e){
e.printStackTrace();
List<String> segments = uri.getPathSegments();
if(segments.size() > 1) {
String rawPath = segments.get(1);
if(!rawPath.startsWith("/")){
return rawPath.substring(rawPath.indexOf("/"));
}else {
return rawPath;
}
}
}
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* Convert Uri into File, if possible.
*
* @return file A local file that the Uri was pointing to, or null if the
* Uri is unsupported or pointed to a remote resource.
* @author paulburke
* @see #getPath(Context, Uri)
*/
public static File getFile(Context context, Uri uri) {
if (uri != null) {
String path = getPath(context, uri);
if (path != null && isLocal(path)) {
return new File(path);
}
}
return null;
}
/**
* Get the file size in a human-readable string.
*
* @param size
* @return
* @author paulburke
*/
public static String getReadableFileSize(int size) {
final int BYTES_IN_KILOBYTES = 1024;
final DecimalFormat dec = new DecimalFormat("###.#");
final String KILOBYTES = " KB";
final String MEGABYTES = " MB";
final String GIGABYTES = " GB";
float fileSize = 0;
String suffix = KILOBYTES;
if (size > BYTES_IN_KILOBYTES) {
fileSize = size / BYTES_IN_KILOBYTES;
if (fileSize > BYTES_IN_KILOBYTES) {
fileSize = fileSize / BYTES_IN_KILOBYTES;
if (fileSize > BYTES_IN_KILOBYTES) {
fileSize = fileSize / BYTES_IN_KILOBYTES;
suffix = GIGABYTES;
} else {
suffix = MEGABYTES;
}
}
}
return String.valueOf(dec.format(fileSize) + suffix);
}
/**
* Attempt to retrieve the thumbnail of given File from the MediaStore. This
* should not be called on the UI thread.
*
* @param context
* @param file
* @return
* @author paulburke
*/
public static Bitmap getThumbnail(Context context, File file) {
return getThumbnail(context, getUri(file), getMimeType(file));
}
/**
* Attempt to retrieve the thumbnail of given Uri from the MediaStore. This
* should not be called on the UI thread.
*
* @param context
* @param uri
* @return
* @author paulburke
*/
public static Bitmap getThumbnail(Context context, Uri uri) {
return getThumbnail(context, uri, getMimeType(context, uri));
}
/**
* Attempt to retrieve the thumbnail of given Uri from the MediaStore. This
* should not be called on the UI thread.
*
* @param context
* @param uri
* @param mimeType
* @return
* @author paulburke
*/
public static Bitmap getThumbnail(Context context, Uri uri, String mimeType) {
if (DEBUG)
Log.d(TAG, "Attempting to quickGet thumbnail");
if (!isMediaUri(uri)) {
Log.e(TAG, "You can only retrieve thumbnails for images and videos.");
return null;
}
Bitmap bm = null;
if (uri != null) {
final ContentResolver resolver = context.getContentResolver();
Cursor cursor = null;
try {
cursor = resolver.query(uri, null, null, null, null);
if (cursor.moveToFirst()) {
final int id = cursor.getInt(0);
if (DEBUG)
Log.d(TAG, "Got thumb ID: " + id);
if (mimeType.contains("video")) {
bm = MediaStore.Video.Thumbnails.getThumbnail(
resolver,
id,
MediaStore.Video.Thumbnails.MINI_KIND,
null);
} else if (mimeType.contains(FileUtils.MIME_TYPE_IMAGE)) {
bm = MediaStore.Images.Thumbnails.getThumbnail(
resolver,
id,
MediaStore.Images.Thumbnails.MINI_KIND,
null);
}
}
} catch (Exception e) {
if (DEBUG)
Log.e(TAG, "getThumbnail", e);
} finally {
if (cursor != null)
cursor.close();
}
}
return bm;
}
/**
* File and folder comparator. TODO Expose sorting option method
*
* @author paulburke
*/
public static Comparator<File> sComparator = new Comparator<File>() {
@Override
public int compare(File f1, File f2) {
// Sort alphabetically by lower case, which is much cleaner
return f1.getName().toLowerCase().compareTo(
f2.getName().toLowerCase());
}
};
/**
* File (not directories) filter.
*
* @author paulburke
*/
public static FileFilter sFileFilter = new FileFilter() {
@Override
public boolean accept(File file) {
final String fileName = file.getName();
// Return files only (not directories) and skip hidden files
return file.isFile() && !fileName.startsWith(HIDDEN_PREFIX);
}
};
/**
* Folder (directories) filter.
*
* @author paulburke
*/
public static FileFilter sDirFilter = new FileFilter() {
@Override
public boolean accept(File file) {
final String fileName = file.getName();
// Return directories only and skip hidden directories
return file.isDirectory() && !fileName.startsWith(HIDDEN_PREFIX);
}
};
/**
* Get the Intent for selecting content to be used in an Intent Chooser.
*
* @return The intent for opening a file with Intent.createChooser()
* @author paulburke
*/
public static Intent createGetContentIntent() {
// Implicitly allow the user to select a particular kind of data
final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
// The MIME data type filter
intent.setType("*/*");
// Only return URIs that can be opened with ContentResolver
intent.addCategory(Intent.CATEGORY_OPENABLE);
return intent;
}
}
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);