URI से फ़ाइल का नाम कैसे निकालना है Intent.ACTION_GET_CONTENT से लौटे?


98

मैं फ़ाइल सिस्टम से फ़ाइल (मेरे मामले में पीडीएफ) लेने के लिए तीसरे पक्ष के फ़ाइल प्रबंधक का उपयोग कर रहा हूं।

इस तरह से मैंने गतिविधि शुरू की:

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);
            }
        }
    }
}

कोड स्निपेट ओपन इंटेंट्स फ़ाइल मैनेजर के निर्देशों से उधार लिया गया है:
http://www.openintents.org/en/node/829

इसका उद्देश्य if-elseपश्चगामी अनुकूलता है। मुझे आश्चर्य है कि अगर फ़ाइल नाम प्राप्त करने का यह सबसे अच्छा तरीका है जैसा कि मैंने पाया है कि अन्य फ़ाइल प्रबंधक सभी प्रकार की चीजें वापस करते हैं।

उदाहरण के लिए, दस्तावेज़ ToGo निम्नलिखित की तरह कुछ लौटाता है:

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

जिस पर getContentResolver().query()लौटता है null

चीजों को अधिक रोचक बनाने के लिए, अनाम फ़ाइल प्रबंधक (मुझे क्लाइंट लॉग से यह यूआरआई मिला) कुछ इस तरह लौटा:

/./sdcard/downloads/.bin


क्या URI से फ़ाइल नाम निकालने का एक पसंदीदा तरीका है या किसी को स्ट्रिंग पार्सिंग का सहारा लेना चाहिए?


शायद बेहतर जवाब के साथ एक ही सवाल: stackoverflow.com/questions/8646246/…
Rémi

जवाबों:


160

developer.android.com के पास इसके लिए अच्छा उदाहरण कोड है: https://developer.android.com/guide/topics/providers/document-provider.html

फ़ाइल नाम निकालने के लिए एक संक्षिप्त संस्करण (यह मानते हुए कि "यह एक गतिविधि है)":

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 या फ़ाइल का नाम पढ़ा प्रयास करते हैं, सबसे पहले आप MediaScanner कि परिवर्तित कर देंगे सूचित करने के लिए है यूआरआई से अपने अभी बनाया फ़ाइल के file://लिए content://में onScanCompleted(String path, Uri uri)विधि stackoverflow.com/a/5815005/2163045
murt

10
new String[]{OpenableColumns.DISPLAY_NAME}क्वेरी के लिए दूसरे पैरामीटर के रूप में जोड़ना अधिक कुशल अनुरोध के लिए कॉलम को फ़िल्टर करेगा।
जेएम लॉर्ड

OpenableColumns.DISPLAY_NAMEमेरे लिए काम नहीं किया, मैं MediaStore.Files.FileColumns.TITLEइसके बजाय इस्तेमाल किया।
दिमित्री कोपिटोव

java.lang.IllegalArgumentException: Invalid column latitudeदुर्भाग्य से कर्सर बनाते समय यह वीडियो के लिए क्रैश हो जाएगा । हालांकि तस्वीरों के लिए पूरी तरह से काम करता है!
लुकास पी।

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
मैंने आपके कोड पर कुछ परीक्षण चलाए हैं। UI पर OI फ़ाइल प्रबंधक IllegalArgumentException द्वारा लौटाया गया है, क्योंकि स्तंभ 'शीर्षक' मौजूद नहीं है। URI द्वारा दस्तावेज़ ToGo कर्सर द्वारा पुनर्प्राप्त करने पर शून्य है। URI पर अज्ञात फ़ाइल प्रबंधक योजना द्वारा लौटाया गया (जाहिर है) अशक्त है।
विक्टर ब्रेजन

2
हां दिलचस्प। हाँ, योजना के लिए परीक्षण! = अशक्त एक अच्छा विचार है। वास्तव में मुझे नहीं लगता कि TITLE वह है जो आप चाहते हैं। मैं इसका उपयोग कर रहा था क्योंकि एंड्रॉइड में कुछ मीडिया प्रकार (जैसे संगीत बीनने वाले के माध्यम से चुने गए गीत) में यूआरआई की सामग्री है: // मीडिया / बाहरी / ऑडियो / मीडिया / 78 और मैं आईडी नंबर से अधिक प्रासंगिक कुछ प्रदर्शित करना चाहता था। आप बस uri.getLastPathSegment () का उपयोग कर सकते हैं जैसे कि मेरे कोड फ़ाइल के लिए उपयोग करता है: // URI यदि आपके पास सामग्री जैसा URI है: //...somefile.pdf
केन

1
uri.getLastPathSegment (); - आपने मेरा दिन बचा लिया है :)
लुमिस

@Ken Fehling: यह मेरे लिए काम नहीं किया। यह काम करता है जब मैं किसी फ़ाइल ब्राउज़र में फ़ाइल क्लिक करता हूं, लेकिन जब मैं ईमेल अनुलग्नक पर क्लिक करता हूं, तब भी मुझे सामग्री मिलती है: // ... बात। मैंने यहां बिना किस्मत के सभी सुझावों को आजमाया। कोई विचार क्यों?
लुइस ए। फ्लोरिट

1
हाय, डी क्यों cursorनहीं है close()?
fikr4n

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

7
धन्यवाद। अच्छा स्वामी उन्हें इतनी तुच्छ चीज़ को इतना परेशान क्यों करना पड़ता है?
TylerJames

1
यह केवल सामग्री फ़ाइलों के साथ काम करता है। पूरी विधि के लिए stackoverflow.com/a/25005243/6325722 देखें
जॉनी फाइव

17

यदि आप इसे कम चाहते हैं तो यह काम करना चाहिए।

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

1
मुझे file.getName () के साथ एक नाम मिल रहा है, लेकिन इसका वास्तविक नाम नहीं है
तुषार ठाकुर

1
मेरा फ़ाइलनाम user.jpg है, लेकिन मुझे प्रतिक्रिया में "6550" मिल रहा है
तुषार ठाकुर

1
यह वास्तविक फ़ाइल नाम वापस नहीं करता है। वास्तव में यह आपके संसाधन url का अंतिम भाग है।
इमदादुल सवोन

यह फ़ाइल के रूप में काम नहीं करता है! ज्यादातर URI को आज MediaStore द्वारा डिकोड किया जाना है। कारण कि मुझे और अन्य को नंबर मिल रहे हैं। क्योंकि वे उन फाइलों की आईडी हैं।
सूद 7००

यह 4 साल पहले दी गई प्रतिक्रिया थी। एंड्रॉइड जाहिर तौर पर हर रिलीज़ को बदल रहा है।
शमूएल

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

मैं अपने प्रोजेक्ट में फ़ाइल नाम और फ़ाइल का आकार उरी से प्राप्त करने के लिए नीचे दिए गए कोड का उपयोग करता हूं।

/**
 * 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() {

    }
}

बाहरी या आंतरिक डेटा से फ़ाइल नाम लोड करने में मेरी समस्या को हल करने में मदद की! बहुत उपयोगी धन्यवाद!
ब्रैंडन

5

कोटलिन के लिए, आप कुछ इस तरह का उपयोग कर सकते हैं:

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 को हटा दें और इसे extention के रूप में उपयोग करें, उदाहरण के लिए: val txtFileName = संदर्भ.getFileNameName। (उरी)
एलेक्सी सिमचेन

@ LumisD आप किसी भी फ़ाइल में इन एक्सटेंशनों को आयात कर सकते हैं, आपका सुझाव सही है लेकिन मुझे सिर्फ नफरत है जब तरीके वैश्विक होते हैं। मैं कुछ विधियों को केवल तभी देखना चाहता हूं जब मैं उन्हें आयात करूं और हमेशा नहीं। और कभी-कभी मैं एक ही विधि के नाम और अलग-अलग स्रोत होना पसंद करता हूं, इसलिए मैं उन लोगों को आयात करता हूं जिनकी मुझे सही जगह पर आवश्यकता है :)
तमीम अताफी

आप इसे इस तरह से आयात कर सकते हैं: com.example.FileUtils.getFileName आयात करें या केवल संदर्भ लिखें ।getFileName (uri) लिखें और Alt + Enter दबाएं और आपका IDE आपके लिए यह काम करेगा :)
तमीम अत्तुमी

5

सबसे गाढ़ा संस्करण:

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

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;
}

यह मेरे मामले में काम नहीं किया, लेकिन वसंत का जवाब था।
नाभि

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

4
क्या आप थोड़ा समझा सकते हैं कि आपका कोड क्या करता है? इस तरह आपका जवाब इस मुद्दे पर ठोकर खाने वाले अन्य उपयोगकर्ताओं के लिए अधिक उपयोगी होगा। धन्यवाद
wmk

किसी कारण से यह मार्शमॉलो पर काम नहीं करता है। यह सिर्फ "ऑडियो और कुछ नंबर" को आउटपुट करता है
एलेक्स

1

जवाब का मेरा संस्करण वास्तव में @Stefan Haustein के समान है। मुझे Android डेवलपर पृष्ठ पर पुनर्प्राप्त फ़ाइल जानकारी का उत्तर मिला ; इस जानकारी को स्टोरेज एक्सेस फ्रेमवर्क गाइड साइट की तुलना में इस विशिष्ट विषय पर और भी अधिक संघनित किया गया है । क्वेरी से परिणाम में फ़ाइल नाम वाला कॉलम इंडेक्स है 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

ज़ैमरिन / सी # के लिए स्टीफन हास्टीन समारोह:

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

यदि आप एक्सटेंशन के साथ फ़ाइल नाम रखना चाहते हैं तो मैं इसे प्राप्त करने के लिए इस फ़ंक्शन का उपयोग करता हूं। यह google ड्राइव फ़ाइल पिक्स के साथ भी काम करता है

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

सभी उत्तरों का संयोजन

यहाँ प्रस्तुत सभी उत्तरों को पढ़ने के बाद मैं यहाँ आया हूँ, साथ ही कुछ एयरग्राम ने अपने एसडीके में क्या किया है - एक उपयोगिता जो मैंने गीथब पर खुली रखी है:

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

प्रयोग

बुला के रूप में सरल UriUtils.getDisplayNameSize(),। यह सामग्री का नाम और आकार दोनों प्रदान करता है।

नोट: केवल एक सामग्री के साथ काम करता है: // उड़ी

यहाँ कोड पर एक झलक है:

/**
 * 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;
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.