Android: 获取任意文件的文件名和扩展名
Android: Get file name and extension of any file
我遇到的问题是,我无法从使用 Android 9 的智能手机上选择的文件中提取文件扩展。使用 Android 8 或更少。
当用户选择任何类型的文件时,将调用 onActivityResult。在此方法中,我从 FileUtils class 调用 getPath,因此我可以提取文件扩展名。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Uri uri = new Uri.Builder().build();
if (resultCode == RESULT_OK) {
switch (requestCode) {
case PICKFILE_REQUEST_CODE: {
String path = new File(data.getData().getPath()).getAbsolutePath();
if (path != null) {
uri = data.getData();
path = FileUtils.getPath(getApplicationContext().getContentResolver(), uri);
name = path.substring(path.lastIndexOf("."));
extension = path.substring(path.lastIndexOf(".") + 1);
}
break;
}
}
}
getPath() 来自 FileUtils class (from this repo) 通过 URI 评估文件是哪种文件,但对这种情况负责以下部分:
public static String getPath(final ContentResolver cr, final Uri uri) {
if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final List<Uri> uris = new ArrayList<>();
uris.add(ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)));
uris.add(ContentUris.withAppendedId(
Uri.parse("content://downloads/my_downloads"), Long.valueOf(id)));
uris.add(ContentUris.withAppendedId(
Uri.parse("content://downloads/all_downloads"), Long.valueOf(id)));
String res;
for (int i = 0; i < uris.size(); i++) {
res = getDataColumn(cr, uris.get(i), null, null);
if (res != null) return res;
}
}
}
getDataColumn()查询保存文件物理路径的文件的列:
public static String getDataColumn(ContentResolver cr,
Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String[] projection = {"_data"};
String col = "";
try {
cursor = cr.query(uri, projection, selection, selectionArgs,null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow("_data");
col = cursor.getString(column_index);
}
}finally{ if (cursor != null) cursor.close();}
return col;
}
当我测试它时,我得到的路径类似于:E/AddItemActivity: result, path: /storage/emulated/0/Download/SampleVideo_176x144_1mb.3gp
。
但是 Android 9 路径总是空的。
对于我使用 MediaStore 提取所选文件的名称和扩展名的解决方案。因此,我将 onActivityResult
中的代码替换为以下代码:
String path = new File(data.getData().getPath()).getAbsolutePath();
if(path != null){
uri = data.getData();
String filename;
Cursor cursor = getContentResolver().query(uri,null,null,null,null);
if(cursor == null) filename=uri.getPath();
else{
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Files.FileColumns.DISPLAY_NAME);
filename = cursor.getString(idx);
cursor.close();
}
String name = filename.substring(0,filename.lastIndexOf("."));
String extension = filename.substring(filename.lastIndexOf(".")+1);
}
因此 MediaStore.File.FileColumns.DISPLAY_NAME
可以从使用文件选择器选择的任何文件中获取文件名和扩展名。
fun Uri.getFileNameWithExtension(context: Context): String? {
val name = this.path?.let { path -> File(path).name }.orEmpty()
val extension = MimeTypeMap.getSingleton()
.getExtensionFromMimeType(getMimeType(context)).orEmpty()
return if (name.isNotEmpty() && extension.isNotEmpty()) "$name.$extension" else null
}
fun Uri.getMimeType(context: Context): String? {
return when (scheme) {
ContentResolver.SCHEME_CONTENT -> context.contentResolver.getType(this)
ContentResolver.SCHEME_FILE -> MimeTypeMap.getSingleton().getMimeTypeFromExtension(
MimeTypeMap.getFileExtensionFromUrl(toString()).toLowerCase(Locale.US)
)
else -> null
}
}
我遇到的问题是,我无法从使用 Android 9 的智能手机上选择的文件中提取文件扩展。使用 Android 8 或更少。
当用户选择任何类型的文件时,将调用 onActivityResult。在此方法中,我从 FileUtils class 调用 getPath,因此我可以提取文件扩展名。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Uri uri = new Uri.Builder().build();
if (resultCode == RESULT_OK) {
switch (requestCode) {
case PICKFILE_REQUEST_CODE: {
String path = new File(data.getData().getPath()).getAbsolutePath();
if (path != null) {
uri = data.getData();
path = FileUtils.getPath(getApplicationContext().getContentResolver(), uri);
name = path.substring(path.lastIndexOf("."));
extension = path.substring(path.lastIndexOf(".") + 1);
}
break;
}
}
}
getPath() 来自 FileUtils class (from this repo) 通过 URI 评估文件是哪种文件,但对这种情况负责以下部分:
public static String getPath(final ContentResolver cr, final Uri uri) {
if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final List<Uri> uris = new ArrayList<>();
uris.add(ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)));
uris.add(ContentUris.withAppendedId(
Uri.parse("content://downloads/my_downloads"), Long.valueOf(id)));
uris.add(ContentUris.withAppendedId(
Uri.parse("content://downloads/all_downloads"), Long.valueOf(id)));
String res;
for (int i = 0; i < uris.size(); i++) {
res = getDataColumn(cr, uris.get(i), null, null);
if (res != null) return res;
}
}
}
getDataColumn()查询保存文件物理路径的文件的列:
public static String getDataColumn(ContentResolver cr,
Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String[] projection = {"_data"};
String col = "";
try {
cursor = cr.query(uri, projection, selection, selectionArgs,null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow("_data");
col = cursor.getString(column_index);
}
}finally{ if (cursor != null) cursor.close();}
return col;
}
当我测试它时,我得到的路径类似于:E/AddItemActivity: result, path: /storage/emulated/0/Download/SampleVideo_176x144_1mb.3gp
。
但是 Android 9 路径总是空的。
对于我使用 MediaStore 提取所选文件的名称和扩展名的解决方案。因此,我将 onActivityResult
中的代码替换为以下代码:
String path = new File(data.getData().getPath()).getAbsolutePath();
if(path != null){
uri = data.getData();
String filename;
Cursor cursor = getContentResolver().query(uri,null,null,null,null);
if(cursor == null) filename=uri.getPath();
else{
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Files.FileColumns.DISPLAY_NAME);
filename = cursor.getString(idx);
cursor.close();
}
String name = filename.substring(0,filename.lastIndexOf("."));
String extension = filename.substring(filename.lastIndexOf(".")+1);
}
因此 MediaStore.File.FileColumns.DISPLAY_NAME
可以从使用文件选择器选择的任何文件中获取文件名和扩展名。
fun Uri.getFileNameWithExtension(context: Context): String? {
val name = this.path?.let { path -> File(path).name }.orEmpty()
val extension = MimeTypeMap.getSingleton()
.getExtensionFromMimeType(getMimeType(context)).orEmpty()
return if (name.isNotEmpty() && extension.isNotEmpty()) "$name.$extension" else null
}
fun Uri.getMimeType(context: Context): String? {
return when (scheme) {
ContentResolver.SCHEME_CONTENT -> context.contentResolver.getType(this)
ContentResolver.SCHEME_FILE -> MimeTypeMap.getSingleton().getMimeTypeFromExtension(
MimeTypeMap.getFileExtensionFromUrl(toString()).toLowerCase(Locale.US)
)
else -> null
}
}