Intent.ACTION_GET_CONTENTから返されたURIからファイル名を抽出する方法


98

サードパーティのファイルマネージャーを使用して、ファイルシステムからファイル(私の場合はPDF)を選択しています。

これは私が活動を開始する方法です:

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType(getString(R.string.app_pdf_mime_type));
intent.addCategory(Intent.CATEGORY_OPENABLE);

String chooserName = getString(R.string.Browse);
Intent chooser = Intent.createChooser(intent, chooserName);

startActivityForResult(chooser, ActivityRequests.BROWSE);

これは私が持っているものですonActivityResult

Uri uri = data.getData();
if (uri != null) {
    if (uri.toString().startsWith("file:")) {
        fileName = uri.getPath();
    } else { // uri.startsWith("content:")

        Cursor c = getContentResolver().query(uri, null, null, null, null);

        if (c != null && c.moveToFirst()) {

            int id = c.getColumnIndex(Images.Media.DATA);
            if (id != -1) {
                fileName = c.getString(id);
            }
        }
    }
}

コードスニペットは、ここから入手できるOpen Intents File Managerの手順から借用しています。http
//www.openintents.org/en/node/829

の目的if-elseは、下位互換性です。他のファイルマネージャーがあらゆる種類のものを返すことがわかったので、これがファイル名を取得するための最良の方法かどうか疑問に思います。

たとえば、Documents ToGoは次のようなものを返します。

content://com.dataviz.dxtg.documentprovider/document/file%3A%2F%2F%2Fsdcard%2Fdropbox%2FTransfer%2Fconsent.pdf

上にgetContentResolver().query()戻りますnull

さらに興味深いことに、名前のないファイルマネージャ(このURIはクライアントログから取得しました)は次のようなものを返しました。

/./sdcard/downloads/.bin


URIからファイル名を抽出する好ましい方法はありますか、それとも文字列解析に頼るべきですか?


多分良い答えと同じ質問:stackoverflow.com/questions/8646246/...
レミ

回答:


159

developer.android.comには、このための素晴らしいサンプルコードがあります:https : //developer.android.com/guide/topics/providers/document-provider.html

ファイル名のみを抽出するための圧縮バージョン( "this"はアクティビティであると想定):

public String getFileName(Uri uri) {
  String result = null;
  if (uri.getScheme().equals("content")) {
    Cursor cursor = getContentResolver().query(uri, null, null, null, null);
    try {
      if (cursor != null && cursor.moveToFirst()) {
        result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
      }
    } finally {
      cursor.close();
    }
  }
  if (result == null) {
    result = uri.getPath();
    int cut = result.lastIndexOf('/');
    if (cut != -1) {
      result = result.substring(cut + 1);
    }
  }
  return result;
}

カメラからファイルのmimeTypeまたはfileNameを読み取ろうとした場合は、まずMediaScannerに通知して、作成したばかりのファイルのURIをメソッドstackoverflow.com/a/5815005/2163045からfile://に変換する必要がありますcontent://onScanCompleted(String path, Uri uri)
murt

10
new String[]{OpenableColumns.DISPLAY_NAME}クエリの2番目のパラメーターとして追加すると、より効率的なリクエストのために列がフィルターされます。
JMロード、

OpenableColumns.DISPLAY_NAMEうまくいきませんでしたMediaStore.Files.FileColumns.TITLE
Dmitry Kopytov

これは、java.lang.IllegalArgumentException: Invalid column latitude残念なことにカーソルを作成するとビデオでクラッシュします。写真でも完璧に動作します!
Lucas P.

44

私はこのようなものを使用しています:

String scheme = uri.getScheme();
if (scheme.equals("file")) {
    fileName = uri.getLastPathSegment();
}
else if (scheme.equals("content")) {
    String[] proj = { MediaStore.Images.Media.TITLE };
    Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
    if (cursor != null && cursor.getCount() != 0) {
        int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.TITLE);
        cursor.moveToFirst();
        fileName = cursor.getString(columnIndex);
    }
    if (cursor != null) {
        cursor.close();
    }
}

4
コードでいくつかのテストを実行しました。OIファイルマネージャーによって返されたURIで、列 'title'が存在しないため、IllegalArgumentExceptionがスローされます。Documents ToGoカーソルで返されたURIがnullです。不明なファイルマネージャスキームによって返されたURIは(明らかに)nullです。
ViktorBrešan11年

2
うーん、面白い。ええ、スキーム!= nullをテストするのは良い考えです。実際、TITLEはあなたが望むものではないと思います。Androidの特定のメディアタイプ(ミュージックピッカーで選択した曲など)にcontent:// media / external / audio / media / 78のようなURIがあり、ID番号よりも関連性の高いものを表示したかったため、これを使用していました。content://...somefile.pdfのようなURIがある場合、私のコードがfile:// URIに使用するように、単にuri.getLastPathSegment()を使用できます
Ken

1
uri.getLastPathSegment(); -あなたは私の日を保存しました:)
Lumis

@ケン・フェーリング:これは私にはうまくいきませんでした。ファイルブラウザーでファイルをクリックすると機能しますが、電子メールの添付ファイルをクリックしても、content:// ...のものが表示されます。私はここですべての提案を運なしで試しました。なぜだろう?
Luis A. Florit 2013年

1
こんにちは、なぜdでcursorはないのclose()ですか?
fikr4n 2013

33

ファイル情報の取得から取得| Android開発者

ファイルの名前を取得します。

private String queryName(ContentResolver resolver, Uri uri) {
    Cursor returnCursor =
            resolver.query(uri, null, null, null, null);
    assert returnCursor != null;
    int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
    returnCursor.moveToFirst();
    String name = returnCursor.getString(nameIndex);
    returnCursor.close();
    return name;
}

1
私はこれをあまりにも長い間探していました!
dasfima 2018年

7
ありがとうございました。善良な主人はなぜ彼らはそのような些細なことをそれほど煩わしくしなければならないのですか?
TylerJames、

1
コンテンツファイルでのみ機能します。完全な方法については、stackoverflow.com / a / 25005243/6325722を参照してください
Johnny Five

17

あなたがそれを短くしたいなら、これはうまくいくはずです。

Uri uri= data.getData();
File file= new File(uri.getPath());
file.getName();

1
file.getName()で名前を取得していますが、実際の名前ではありません
Tushar Thakur '12 / 07/12

1
私のfileNameはuser.jpgですが、応答として「6550」を取得しています
Tushar Thakur

1
実際のファイル名は返しません。実際には、リソースURLの最後の部分を返します。
Emdadul Sawon 2017

これはファイルとしては機能しません!ほとんどの場合、URIは今日MediaStoreでデコードする必要があります。私や他の人が数を取得している理由。それらはそれらのファイルのIDだからです。
sud007

これは4年前の回答でした。Androidは明らかにすべてのリリースを変更しています。
サミュエル

17

ファイル名を取得する最も簡単な方法:

val fileName = File(uri.path).name
// or
val fileName = uri.pathSegments.last()

彼らがあなたに正しい名前を与えないなら、あなたは使うべきです:

fun Uri.getName(context: Context): String {
    val returnCursor = context.contentResolver.query(this, null, null, null, null)
    val nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
    returnCursor.moveToFirst()
    val fileName = returnCursor.getString(nameIndex)
    returnCursor.close()
    return fileName
}

7

以下のコードを使用して、プロジェクトのUriからファイル名とファイルサイズを取得します。

/**
 * Used to get file detail from uri.
 * <p>
 * 1. Used to get file detail (name & size) from uri.
 * 2. Getting file details from uri is different for different uri scheme,
 * 2.a. For "File Uri Scheme" - We will get file from uri & then get its details.
 * 2.b. For "Content Uri Scheme" - We will get the file details by querying content resolver.
 *
 * @param uri Uri.
 * @return file detail.
 */
public static FileDetail getFileDetailFromUri(final Context context, final Uri uri) {
    FileDetail fileDetail = null;
    if (uri != null) {
        fileDetail = new FileDetail();
        // File Scheme.
        if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
            File file = new File(uri.getPath());
            fileDetail.fileName = file.getName();
            fileDetail.fileSize = file.length();
        }
        // Content Scheme.
        else if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
            Cursor returnCursor =
                    context.getContentResolver().query(uri, null, null, null, null);
            if (returnCursor != null && returnCursor.moveToFirst()) {
                int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
                int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
                fileDetail.fileName = returnCursor.getString(nameIndex);
                fileDetail.fileSize = returnCursor.getLong(sizeIndex);
                returnCursor.close();
            }
        }
    }
    return fileDetail;
}

/**
 * File Detail.
 * <p>
 * 1. Model used to hold file details.
 */
public static class FileDetail {

    // fileSize.
    public String fileName;

    // fileSize in bytes.
    public long fileSize;

    /**
     * Constructor.
     */
    public FileDetail() {

    }
}

外部または内部データからのファイル名の読み込みに関する私の問題の解決に役立ちました!とても便利です!
ブランドン、

4
public String getFilename() 
{
/*  Intent intent = getIntent();
    String name = intent.getData().getLastPathSegment();
    return name;*/
    Uri uri=getIntent().getData();
    String fileName = null;
    Context context=getApplicationContext();
    String scheme = uri.getScheme();
    if (scheme.equals("file")) {
        fileName = uri.getLastPathSegment();
    }
    else if (scheme.equals("content")) {
        String[] proj = { MediaStore.Video.Media.TITLE };
        Uri contentUri = null;
        Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null);
        if (cursor != null && cursor.getCount() != 0) {
            int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.TITLE);
            cursor.moveToFirst();
            fileName = cursor.getString(columnIndex);
        }
    }
    return fileName;
}

これは私の場合はうまくいきませんでしたが、Vasanthの答えはうまくいきました。
ナブジ

4

Kotlinの場合、次のようなものを使用できます。

object FileUtils {

   fun Context.getFileName(uri: Uri): String?
        = when (uri.scheme) {
            ContentResolver.SCHEME_FILE -> File(uri.path).name
            ContentResolver.SCHEME_CONTENT -> getCursorContent(uri)
            else -> null
        }

    private fun Context.getCursorContent(uri: Uri): String? 
        = try {
            contentResolver.query(uri, null, null, null, null)?.let { cursor ->
                cursor.run {
                    if (moveToFirst()) getString(getColumnIndex(OpenableColumns.DISPLAY_NAME))
                    else null
                }.also { cursor.close() }
            }
        } catch (e : Exception) { null }

良い答えですが、私の意見では、これらのファン(Context.getFileNameおよびContext.getCursorContent)を「Context」という名前のファイルに挿入し、単語オブジェクトFileUtilsを削除して、拡張として使用します。例:val txtFileName = context.getFileName (uri)
Alexey Simchenko

@LumisDあなたはこれらの拡張子を任意のファイルにインポートできます、あなたの提案は正しいですが、メソッドがグローバルであるとき私はただ嫌いです。特定のメソッドを常にインポートするのではなく、インポートする場合にのみ表示したい。また、同じメソッド名と異なるソースを使用したい場合があるため、必要なものを適切な場所にインポートします:)
Tamim Attafi

次の方法でインポートできます
。com.example.FileUtils.getFileNameを

4

最も凝縮されたバージョン:

public String getNameFromURI(Uri uri) {
    Cursor c = getContentResolver().query(uri, null, null, null, null);
    c.moveToFirst();
    return c.getString(c.getColumnIndex(OpenableColumns.DISPLAY_NAME));
}

1
カーソルを閉じることを忘れないでください:)
BekaBot

2
String Fpath = getPath(this, uri) ;
File file = new File(Fpath);
String filename = file.getName();

4
あなたのコードが何をしているのか少し説明してもらえますか?このようにして、あなたの答えは、この問題に出くわした他のユーザーにとってより役立つでしょう。ありがとう
wmk

何らかの理由で、これはmarshmellowでは機能しません。それは単に「オーディオといくつかの数」を出力する
アレックス

1

私の回答のバージョンは、実際には@Stefan Hausteinに非常に似ています。Androidデベロッパーページのファイル情報の取得で答えを見つけました。ここでの情報は、Storage Access Frameworkガイドサイトよりも、この特定のトピックにさらに凝縮されています。クエリの結果では、ファイル名を含む列インデックスはOpenableColumns.DISPLAY_NAMEです。列インデックスに関する他の回答/解決策はどれも私にとってうまくいきませんでした。以下はサンプル関数です:

 /**
 * @param uri uri of file.
 * @param contentResolver access to server app.
 * @return the name of the file.
 */
def extractFileName(uri: Uri, contentResolver: ContentResolver): Option[String] = {

    var fileName: Option[String] = None
    if (uri.getScheme.equals("file")) {

        fileName = Option(uri.getLastPathSegment)
    } else if (uri.getScheme.equals("content")) {

        var cursor: Cursor = null
        try {

            // Query the server app to get the file's display name and size.
            cursor = contentResolver.query(uri, null, null, null, null)

            // Get the column indexes of the data in the Cursor,
            // move to the first row in the Cursor, get the data.
            if (cursor != null && cursor.moveToFirst()) {

                val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
                fileName = Option(cursor.getString(nameIndex))
            }

        } finally {

            if (cursor != null) {
                cursor.close()
            }

        }

    }

    fileName
}

1

まず、URIオブジェクトをURLオブジェクトに変換し、次にFileオブジェクトを使用してファイル名を取得する必要があります。

try
    {
        URL videoUrl = uri.toURL();
        File tempFile = new File(videoUrl.getFile());
        String fileName = tempFile.getName();
    }
    catch (Exception e)
    {

    }

それだけです。とても簡単です。


1

xamarin / c#のStefan Haustein関数:

public string GetFilenameFromURI(Android.Net.Uri uri)
        {
            string result = null;
            if (uri.Scheme == "content")
            {
                using (var cursor = Application.Context.ContentResolver.Query(uri, null, null, null, null))
                {
                    try
                    {
                        if (cursor != null && cursor.MoveToFirst())
                        {
                            result = cursor.GetString(cursor.GetColumnIndex(OpenableColumns.DisplayName));
                        }
                    }
                    finally
                    {
                        cursor.Close();
                    }
                }
            }
            if (result == null)
            {
                result = uri.Path;
                int cut = result.LastIndexOf('/');
                if (cut != -1)
                {
                    result = result.Substring(cut + 1);
                }
            }
            return result;
        }

1

ファイル名に拡張子を付けたい場合は、この関数を使用して取得します。それはまたグーグルドライブファイルピックで動作します

public static String getFileName(Uri uri) {
    String result;

    //if uri is content
    if (uri.getScheme() != null && uri.getScheme().equals("content")) {
        Cursor cursor = global.getInstance().context.getContentResolver().query(uri, null, null, null, null);
        try {
            if (cursor != null && cursor.moveToFirst()) {
                //local filesystem
                int index = cursor.getColumnIndex("_data");
                if(index == -1)
                    //google drive
                    index = cursor.getColumnIndex("_display_name");
                result = cursor.getString(index);
                if(result != null)
                    uri = Uri.parse(result);
                else
                    return null;
            }
        } finally {
            cursor.close();
        }
    }

    result = uri.getPath();

    //get filename + ext of path
    int cut = result.lastIndexOf('/');
    if (cut != -1)
        result = result.substring(cut + 1);
    return result;
}

1

これは実際に私のために働きました:

private String uri2filename() {

    String ret;
    String scheme = uri.getScheme();

    if (scheme.equals("file")) {
        ret = uri.getLastPathSegment();
    }
    else if (scheme.equals("content")) {
        Cursor cursor = getContentResolver().query(uri, null, null, null, null);
        if (cursor != null && cursor.moveToFirst()) {
            ret = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
        }
   }
   return ret;
}

0

これを試してください:

  private String displayName(Uri uri) {

             Cursor mCursor =
                     getApplicationContext().getContentResolver().query(uri, null, null, null, null);
             int indexedname = mCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
             mCursor.moveToFirst();
             String filename = mCursor.getString(indexedname);
             mCursor.close();
             return filename;
 }

0

すべての答えの組み合わせ

ここに示されているすべての回答を読んだ後、私が到達したものと、一部のAirgramがSDKで行ったこと-Githubでオープンソース化したユーティリティ:

https://github.com/mankum93/UriUtilsAndroid/tree/master/app/src/main/java/com/androiduriutils

使用法

呼び出すのと同じくらい簡単UriUtils.getDisplayNameSize()です。コンテンツの名前とサイズの両方を提供します。

注: content:// Uriでのみ機能します

これがコードの一部です。

/**
 * References:
 * - https://www.programcreek.com/java-api-examples/?code=MLNO/airgram/airgram-master/TMessagesProj/src/main/java/ir/hamzad/telegram/MediaController.java
 * - /programming/5568874/how-to-extract-the-file-name-from-uri-returned-from-intent-action-get-content
 *
 * @author Manish@bit.ly/2HjxA0C
 * Created on: 03-07-2020
 */
public final class UriUtils {


    public static final int CONTENT_SIZE_INVALID = -1;

    /**
     * @param context context
     * @param contentUri content Uri, i.e, of the scheme <code>content://</code>
     * @return The Display name and size for content. In case of non-determination, display name
     * would be null and content size would be {@link #CONTENT_SIZE_INVALID}
     */
    @NonNull
    public static DisplayNameAndSize getDisplayNameSize(@NonNull Context context, @NonNull Uri contentUri){

        final String scheme = contentUri.getScheme();
        if(scheme == null || !scheme.equals(ContentResolver.SCHEME_CONTENT)){
            throw new RuntimeException("Only scheme content:// is accepted");
        }

        final DisplayNameAndSize displayNameAndSize = new DisplayNameAndSize();
        displayNameAndSize.size = CONTENT_SIZE_INVALID;

        String[] projection = new String[]{MediaStore.Images.Media.DATA, OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE};
        Cursor cursor = context.getContentResolver().query(contentUri, projection, null, null, null);
        try {
            if (cursor != null && cursor.moveToFirst()) {

                // Try extracting content size

                int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
                if (sizeIndex != -1) {
                    displayNameAndSize.size = cursor.getLong(sizeIndex);
                }

                // Try extracting display name
                String name = null;

                // Strategy: The column name is NOT guaranteed to be indexed by DISPLAY_NAME
                // so, we try two methods
                int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
                if (nameIndex != -1) {
                    name = cursor.getString(nameIndex);
                }

                if (nameIndex == -1 || name == null) {
                    nameIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
                    if (nameIndex != -1) {
                        name = cursor.getString(nameIndex);
                    }
                }
                displayNameAndSize.displayName = name;
            }
        }
        finally {
            if(cursor != null){
                cursor.close();
            }
        }

        // We tried querying the ContentResolver...didn't work out
        // Try extracting the last path segment
        if(displayNameAndSize.displayName == null){
            displayNameAndSize.displayName = contentUri.getLastPathSegment();
        }

        return displayNameAndSize;
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.