শেয়ার্ড স্টোরেজ থেকে নথি এবং অন্যান্য ফাইল অ্যাক্সেস করুন

যে ডিভাইসগুলিতে Android 4.4 (API স্তর 19) এবং উচ্চতর চলে, আপনার অ্যাপ স্টোরেজ অ্যাক্সেস ফ্রেমওয়ার্ক ব্যবহার করে বাহ্যিক স্টোরেজ ভলিউম এবং ক্লাউড-ভিত্তিক স্টোরেজ সহ একটি নথি প্রদানকারীর সাথে যোগাযোগ করতে পারে। এই ফ্রেমওয়ার্ক ব্যবহারকারীদের একটি নথি প্রদানকারী চয়ন করতে এবং আপনার অ্যাপ তৈরি, খোলা বা সংশোধন করার জন্য নির্দিষ্ট নথি এবং অন্যান্য ফাইল নির্বাচন করতে একটি সিস্টেম পিকারের সাথে যোগাযোগ করতে দেয়৷

যেহেতু ব্যবহারকারী আপনার অ্যাপ অ্যাক্সেস করতে পারে এমন ফাইল বা ডিরেক্টরি নির্বাচন করার সাথে জড়িত, এই প্রক্রিয়াটির জন্য কোনো সিস্টেম অনুমতির প্রয়োজন হয় না এবং ব্যবহারকারীর নিয়ন্ত্রণ এবং গোপনীয়তা উন্নত হয়৷ উপরন্তু, এই ফাইলগুলি, যেগুলি একটি অ্যাপ-নির্দিষ্ট ডিরেক্টরির বাইরে এবং মিডিয়া স্টোরের বাইরে সংরক্ষণ করা হয়, আপনার অ্যাপ আনইনস্টল করার পরে ডিভাইসে থেকে যায়।

ফ্রেমওয়ার্ক ব্যবহারে নিম্নলিখিত পদক্ষেপগুলি জড়িত:

  1. একটি অ্যাপ এমন একটি অভিপ্রায় আহ্বান করে যাতে একটি স্টোরেজ-সম্পর্কিত ক্রিয়া থাকে। এই ক্রিয়াটি একটি নির্দিষ্ট ব্যবহারের ক্ষেত্রের সাথে মিলে যায় যা ফ্রেমওয়ার্ক উপলব্ধ করে।
  2. ব্যবহারকারী একটি সিস্টেম পিকার দেখেন, তাদের একটি নথি প্রদানকারীকে ব্রাউজ করার অনুমতি দেয় এবং স্টোরেজ-সম্পর্কিত ক্রিয়াকলাপ সঞ্চালিত হয় এমন একটি অবস্থান বা নথি বেছে নিতে দেয়।
  3. অ্যাপটি একটি URI-তে পড়ার এবং লেখার অ্যাক্সেস লাভ করে যা ব্যবহারকারীর নির্বাচিত অবস্থান বা নথির প্রতিনিধিত্ব করে। এই URI ব্যবহার করে, অ্যাপটি নির্বাচিত স্থানে অপারেশন করতে পারে।

Android 9 (API লেভেল 28) বা তার নিচের ডিভাইসগুলিতে মিডিয়া ফাইল অ্যাক্সেস সমর্থন করতে, READ_EXTERNAL_STORAGE অনুমতি ঘোষণা করুন এবং maxSdkVersion 28 এ সেট করুন।

এই নির্দেশিকাটি ফাইল এবং অন্যান্য নথির সাথে কাজ করার জন্য ফ্রেমওয়ার্ক সমর্থন করে এমন বিভিন্ন ব্যবহারের ক্ষেত্রে ব্যাখ্যা করে। এটি ব্যবহারকারী-নির্বাচিত অবস্থানে কীভাবে ক্রিয়াকলাপ সম্পাদন করতে হয় তাও ব্যাখ্যা করে।

নথি এবং অন্যান্য ফাইল অ্যাক্সেস করার জন্য কেস ব্যবহার করুন

স্টোরেজ অ্যাক্সেস ফ্রেমওয়ার্ক ফাইল এবং অন্যান্য নথি অ্যাক্সেস করার জন্য নিম্নলিখিত ব্যবহারের ক্ষেত্রে সমর্থন করে।

একটি নতুন ফাইল তৈরি করুন
ACTION_CREATE_DOCUMENT অভিপ্রায় ক্রিয়া ব্যবহারকারীদের একটি নির্দিষ্ট স্থানে একটি ফাইল সংরক্ষণ করতে দেয়৷
একটি নথি বা ফাইল খুলুন
ACTION_OPEN_DOCUMENT অভিপ্রায় ক্রিয়া ব্যবহারকারীদের খোলার জন্য একটি নির্দিষ্ট নথি বা ফাইল নির্বাচন করতে দেয়৷
একটি ডিরেক্টরির বিষয়বস্তু অ্যাক্সেস মঞ্জুর করুন
ACTION_OPEN_DOCUMENT_TREE ইন্টেন্ট অ্যাকশন, Android 5.0 (API লেভেল 21) এবং উচ্চতর সংস্করণে উপলব্ধ, ব্যবহারকারীদের একটি নির্দিষ্ট ডিরেক্টরি নির্বাচন করার অনুমতি দেয়, সেই ডিরেক্টরির মধ্যে থাকা সমস্ত ফাইল এবং সাব-ডিরেক্টরিগুলিতে আপনার অ্যাপের অ্যাক্সেস মঞ্জুর করে৷

নিম্নলিখিত বিভাগগুলি প্রতিটি ব্যবহারের ক্ষেত্রে কীভাবে কনফিগার করতে হয় তার নির্দেশিকা প্রদান করে।

একটি নতুন ফাইল তৈরি করুন

সিস্টেম ফাইল পিকার লোড করতে ACTION_CREATE_DOCUMENT ইন্টেন্ট অ্যাকশন ব্যবহার করুন এবং ব্যবহারকারীকে একটি ফাইলের বিষয়বস্তু কোথায় লিখতে হবে তা বেছে নেওয়ার অনুমতি দিন। এই প্রক্রিয়াটি অন্যান্য অপারেটিং সিস্টেম ব্যবহার করে "সেভ অ্যাজ" ডায়ালগে ব্যবহৃত একটির মতো।

দ্রষ্টব্য: ACTION_CREATE_DOCUMENT একটি বিদ্যমান ফাইল ওভাররাইট করতে পারে না৷ যদি আপনার অ্যাপ একই নামের একটি ফাইল সংরক্ষণ করার চেষ্টা করে, তাহলে সিস্টেমটি ফাইলের নামের শেষে বন্ধনীতে একটি সংখ্যা যুক্ত করে।

উদাহরণস্বরূপ, যদি আপনার অ্যাপটি confirmation.pdf নামে একটি ফাইল সংরক্ষণ করার চেষ্টা করে যেখানে ইতিমধ্যেই সেই নামের একটি ফাইল রয়েছে, তাহলে সিস্টেমটি নতুন ফাইলটিকে নাম confirmation(1).pdf সহ সংরক্ষণ করে।

অভিপ্রায় কনফিগার করার সময়, ফাইলের নাম এবং MIME প্রকার উল্লেখ করুন, এবং ঐচ্ছিকভাবে ফাইল বা ডিরেক্টরির URI নির্দিষ্ট করুন যেটি ফাইল পিকার যখন EXTRA_INITIAL_URI অতিরিক্ত ব্যবহার করে প্রথম লোড হয় তখন প্রদর্শন করা উচিত৷

নিম্নলিখিত কোড স্নিপেট দেখায় কিভাবে একটি ফাইল তৈরি করার উদ্দেশ্য তৈরি এবং আহ্বান করা যায়:

কোটলিন

// Request code for creating a PDF document.
const val CREATE_FILE = 1

private fun createFile(pickerInitialUri: Uri) {
    val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
        addCategory(Intent.CATEGORY_OPENABLE)
        type = "application/pdf"
        putExtra(Intent.EXTRA_TITLE, "invoice.pdf")

        // Optionally, specify a URI for the directory that should be opened in
        // the system file picker before your app creates the document.
        putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri)
    }
    startActivityForResult(intent, CREATE_FILE)
}

জাভা

// Request code for creating a PDF document.
private static final int CREATE_FILE = 1;

private void createFile(Uri pickerInitialUri) {
    Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("application/pdf");
    intent.putExtra(Intent.EXTRA_TITLE, "invoice.pdf");

    // Optionally, specify a URI for the directory that should be opened in
    // the system file picker when your app creates the document.
    intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri);

    startActivityForResult(intent, CREATE_FILE);
}

একটি ফাইল খুলুন

আপনার অ্যাপ স্টোরেজের একক হিসাবে ডকুমেন্টগুলি ব্যবহার করতে পারে যেখানে ব্যবহারকারীরা এমন ডেটা প্রবেশ করে যা তারা সহকর্মীদের সাথে ভাগ করতে বা অন্য নথিতে আমদানি করতে চায়। বেশ কয়েকটি উদাহরণের মধ্যে একজন ব্যবহারকারী একটি উত্পাদনশীলতা নথি খুলছেন বা একটি EPUB ফাইল হিসাবে সংরক্ষিত একটি বই খুলছেন।

এই ক্ষেত্রে, ব্যবহারকারীকে ACTION_OPEN_DOCUMENT অভিপ্রায় দিয়ে খোলার জন্য ফাইলটি বেছে নেওয়ার অনুমতি দিন, যা সিস্টেমের ফাইল পিকার অ্যাপটি খুলবে৷ আপনার অ্যাপ সমর্থন করে এমন ফাইলের ধরন দেখাতে, একটি MIME প্রকার নির্দিষ্ট করুন৷ এছাড়াও, আপনি ঐচ্ছিকভাবে ফাইলের URI নির্দিষ্ট করতে পারেন যেটি ফাইল পিকার যখন প্রথম লোড হয় তখন EXTRA_INITIAL_URI অতিরিক্ত ব্যবহার করে প্রদর্শন করা উচিত।

নিম্নলিখিত কোড স্নিপেট দেখায় কিভাবে একটি পিডিএফ ডকুমেন্ট খোলার অভিপ্রায় তৈরি এবং আহ্বান করা যায়:

কোটলিন

// Request code for selecting a PDF document.
const val PICK_PDF_FILE = 2

fun openFile(pickerInitialUri: Uri) {
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
        addCategory(Intent.CATEGORY_OPENABLE)
        type = "application/pdf"

        // Optionally, specify a URI for the file that should appear in the
        // system file picker when it loads.
        putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri)
    }

    startActivityForResult(intent, PICK_PDF_FILE)
}

জাভা

// Request code for selecting a PDF document.
private static final int PICK_PDF_FILE = 2;

private void openFile(Uri pickerInitialUri) {
    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("application/pdf");

    // Optionally, specify a URI for the file that should appear in the
    // system file picker when it loads.
    intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri);

    startActivityForResult(intent, PICK_PDF_FILE);
}

অ্যাক্সেস সীমাবদ্ধতা

Android 11 (API স্তর 30) এবং উচ্চতর, আপনি ACTION_OPEN_DOCUMENT ইন্টেন্ট অ্যাকশন ব্যবহার করতে পারবেন না যাতে ব্যবহারকারী নিম্নলিখিত ডিরেক্টরিগুলি থেকে পৃথক ফাইল নির্বাচন করতে পারেন:

  • Android/data/ ডিরেক্টরি এবং সমস্ত সাবডিরেক্টরি।
  • Android/obb/ ডিরেক্টরি এবং সমস্ত সাবডিরেক্টরি।

একটি ডিরেক্টরির বিষয়বস্তু অ্যাক্সেস মঞ্জুর করুন

ফাইল ম্যানেজমেন্ট এবং মিডিয়া-সৃষ্টি অ্যাপগুলি সাধারণত একটি ডিরেক্টরি অনুক্রমের ফাইলগুলির গ্রুপগুলি পরিচালনা করে। আপনার অ্যাপে এই ক্ষমতা প্রদান করতে, ACTION_OPEN_DOCUMENT_TREE ইন্টেন্ট অ্যাকশন ব্যবহার করুন, যা ব্যবহারকারীকে Android 11 (API লেভেল 30) থেকে শুরু হওয়া কিছু ব্যতিক্রম সহ একটি সম্পূর্ণ ডিরেক্টরি ট্রিতে অ্যাক্সেস দেওয়ার অনুমতি দেয়। আপনার অ্যাপটি তখন নির্বাচিত ডিরেক্টরির যেকোনো ফাইল এবং এর যেকোনো উপ-ডিরেক্টরি অ্যাক্সেস করতে পারে।

ACTION_OPEN_DOCUMENT_TREE ব্যবহার করার সময়, আপনার অ্যাপ্লিকেশানটি শুধুমাত্র ব্যবহারকারীর নির্বাচিত ডিরেক্টরির ফাইলগুলিতে অ্যাক্সেস লাভ করে৷ এই ব্যবহারকারী-নির্বাচিত ডিরেক্টরির বাইরে থাকা অন্যান্য অ্যাপের ফাইলগুলিতে আপনার অ্যাক্সেস নেই৷ এই ব্যবহারকারী-নিয়ন্ত্রিত অ্যাক্সেস ব্যবহারকারীদের ঠিক কোন বিষয়বস্তু আপনার অ্যাপের সাথে শেয়ার করতে স্বাচ্ছন্দ্য বোধ করে তা চয়ন করতে দেয়৷

ঐচ্ছিকভাবে, আপনি EXTRA_INITIAL_URI উদ্দেশ্য অতিরিক্ত ব্যবহার করে ফাইল বাছাইকারীর প্রথম লোড হওয়ার সময় যে ডিরেক্টরিটি প্রদর্শন করা উচিত সেটির URI নির্দিষ্ট করতে পারেন।

নিম্নলিখিত কোড স্নিপেট দেখায় কিভাবে একটি ডিরেক্টরি খোলার জন্য অভিপ্রায় তৈরি এবং আহ্বান করতে হয়:

কোটলিন

fun openDirectory(pickerInitialUri: Uri) {
    // Choose a directory using the system's file picker.
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
        // Optionally, specify a URI for the directory that should be opened in
        // the system file picker when it loads.
        putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri)
    }

    startActivityForResult(intent, your-request-code)
}

জাভা

public void openDirectory(Uri uriToLoad) {
    // Choose a directory using the system's file picker.
    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);

    // Optionally, specify a URI for the directory that should be opened in
    // the system file picker when it loads.
    intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, uriToLoad);

    startActivityForResult(intent, your-request-code);
}

অ্যাক্সেস সীমাবদ্ধতা

Android 11 (API স্তর 30) এবং উচ্চতর, আপনি নিম্নলিখিত ডিরেক্টরিগুলিতে অ্যাক্সেসের অনুরোধ করতে ACTION_OPEN_DOCUMENT_TREE অভিপ্রায় ক্রিয়া ব্যবহার করতে পারবেন না:

  • অভ্যন্তরীণ স্টোরেজ ভলিউমের রুট ডিরেক্টরি।
  • প্রতিটি SD কার্ড ভলিউমের রুট ডিরেক্টরি যা ডিভাইস প্রস্তুতকারক নির্ভরযোগ্য বলে মনে করেন, কার্ডটি অনুকরণ করা বা অপসারণযোগ্য কিনা তা নির্বিশেষে৷ একটি নির্ভরযোগ্য ভলিউম হল একটি অ্যাপ যা সফলভাবে বেশিরভাগ সময় অ্যাক্সেস করতে পারে।
  • Download ডিরেক্টরি।

উপরন্তু, Android 11 (API স্তর 30) এবং উচ্চতর, আপনি ACTION_OPEN_DOCUMENT_TREE অভিপ্রায় ক্রিয়াটি ব্যবহার করতে পারবেন না যাতে ব্যবহারকারী নিম্নলিখিত ডিরেক্টরিগুলি থেকে পৃথক ফাইলগুলি নির্বাচন করেন:

  • Android/data/ ডিরেক্টরি এবং সমস্ত সাবডিরেক্টরি।
  • Android/obb/ ডিরেক্টরি এবং সমস্ত সাবডিরেক্টরি।

নির্বাচিত স্থানে অপারেশন সঞ্চালন

ব্যবহারকারী সিস্টেমের ফাইল পিকার ব্যবহার করে একটি ফাইল বা ডিরেক্টরি নির্বাচন করার পরে, আপনি onActivityResult() এ নিম্নলিখিত কোডটি ব্যবহার করে নির্বাচিত আইটেমের URI পুনরুদ্ধার করতে পারেন:

কোটলিন

override fun onActivityResult(
        requestCode: Int, resultCode: Int, resultData: Intent?) {
    if (requestCode == your-request-code
            && resultCode == Activity.RESULT_OK) {
        // The result data contains a URI for the document or directory that
        // the user selected.
        resultData?.data?.also { uri ->
            // Perform operations on the document using its URI.
        }
    }
}

জাভা

@Override
public void onActivityResult(int requestCode, int resultCode,
        Intent resultData) {
    if (requestCode == your-request-code
            && resultCode == Activity.RESULT_OK) {
        // The result data contains a URI for the document or directory that
        // the user selected.
        Uri uri = null;
        if (resultData != null) {
            uri = resultData.getData();
            // Perform operations on the document using its URI.
        }
    }
}

নির্বাচিত আইটেমটির ইউআরআই-এর একটি রেফারেন্স পেয়ে, আপনার অ্যাপটি আইটেমের উপর বিভিন্ন ক্রিয়াকলাপ সম্পাদন করতে পারে। উদাহরণস্বরূপ, আপনি আইটেমের মেটাডেটা অ্যাক্সেস করতে পারেন, আইটেমটি জায়গায় সম্পাদনা করতে পারেন এবং আইটেমটি মুছতে পারেন৷

নিম্নলিখিত বিভাগগুলি ব্যবহারকারীর নির্বাচন করা ফাইলগুলিতে কর্মগুলি কীভাবে সম্পূর্ণ করতে হয় তা দেখায়।

একটি প্রদানকারী সমর্থন করে এমন অপারেশনগুলি নির্ধারণ করুন

বিভিন্ন বিষয়বস্তু প্রদানকারী নথিতে বিভিন্ন ক্রিয়াকলাপ সম্পাদন করার অনুমতি দেয়—যেমন নথিটি অনুলিপি করা বা একটি নথির থাম্বনেল দেখা। প্রদত্ত প্রদানকারী কোন ক্রিয়াকলাপগুলিকে সমর্থন করে তা নির্ধারণ করতে, Document.COLUMN_FLAGS মান পরীক্ষা করুন৷COLUMN_FLAGS৷ আপনার অ্যাপের UI তারপর শুধুমাত্র সেই বিকল্পগুলি দেখাতে পারে যা প্রদানকারী সমর্থন করে।

অনুমতি অব্যাহত

যখন আপনার অ্যাপ পড়ার বা লেখার জন্য একটি ফাইল খোলে, সিস্টেমটি আপনার অ্যাপটিকে সেই ফাইলের জন্য একটি URI অনুমতি প্রদান করে, যা ব্যবহারকারীর ডিভাইস রিস্টার্ট না হওয়া পর্যন্ত স্থায়ী হয়। ধরুন, যাইহোক, আপনার অ্যাপটি একটি ইমেজ-এডিটিং অ্যাপ, এবং আপনি চান ব্যবহারকারীরা আপনার অ্যাপ থেকে সরাসরি সম্পাদিত 5টি ছবি অ্যাক্সেস করতে পারবে। ব্যবহারকারীর ডিভাইসটি পুনরায় চালু হলে, ফাইলগুলি খুঁজে পেতে আপনাকে ব্যবহারকারীকে সিস্টেম পিকারে ফেরত পাঠাতে হবে।

ডিভাইস রিস্টার্ট জুড়ে ফাইলগুলিতে অ্যাক্সেস সংরক্ষণ করতে এবং আরও ভাল ব্যবহারকারীর অভিজ্ঞতা তৈরি করতে, আপনার অ্যাপটি সিস্টেমের অফার করা স্থায়ী URI অনুমতি মঞ্জুরি "নেতে" পারে, যেমনটি নিম্নলিখিত কোড স্নিপেটে দেখানো হয়েছে:

কোটলিন

val contentResolver = applicationContext.contentResolver

val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or
        Intent.FLAG_GRANT_WRITE_URI_PERMISSION
// Check for the freshest data.
contentResolver.takePersistableUriPermission(uri, takeFlags)

জাভা

final int takeFlags = intent.getFlags()
            & (Intent.FLAG_GRANT_READ_URI_PERMISSION
            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// Check for the freshest data.
getContentResolver().takePersistableUriPermission(uri, takeFlags);

নথির মেটাডেটা পরীক্ষা করুন

যখন আপনার কাছে একটি নথির জন্য URI থাকে, তখন আপনি এর মেটাডেটাতে অ্যাক্সেস পান। এই স্নিপেটটি ইউআরআই দ্বারা নির্দিষ্ট করা একটি নথির জন্য মেটাডেটা দখল করে এবং এটি লগ করে:

কোটলিন

val contentResolver = applicationContext.contentResolver

fun dumpImageMetaData(uri: Uri) {

    // The query, because it only applies to a single document, returns only
    // one row. There's no need to filter, sort, or select fields,
    // because we want all fields for one document.
    val cursor: Cursor? = contentResolver.query(
            uri, null, null, null, null, null)

    cursor?.use {
        // moveToFirst() returns false if the cursor has 0 rows. Very handy for
        // "if there's anything to look at, look at it" conditionals.
        if (it.moveToFirst()) {

            // Note it's called "Display Name". This is
            // provider-specific, and might not necessarily be the file name.
            val displayName: String =
                    it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME))
            Log.i(TAG, "Display Name: $displayName")

            val sizeIndex: Int = it.getColumnIndex(OpenableColumns.SIZE)
            // If the size is unknown, the value stored is null. But because an
            // int can't be null, the behavior is implementation-specific,
            // and unpredictable. So as
            // a rule, check if it's null before assigning to an int. This will
            // happen often: The storage API allows for remote files, whose
            // size might not be locally known.
            val size: String = if (!it.isNull(sizeIndex)) {
                // Technically the column stores an int, but cursor.getString()
                // will do the conversion automatically.
                it.getString(sizeIndex)
            } else {
                "Unknown"
            }
            Log.i(TAG, "Size: $size")
        }
    }
}

জাভা

public void dumpImageMetaData(Uri uri) {

    // The query, because it only applies to a single document, returns only
    // one row. There's no need to filter, sort, or select fields,
    // because we want all fields for one document.
    Cursor cursor = getActivity().getContentResolver()
            .query(uri, null, null, null, null, null);

    try {
        // moveToFirst() returns false if the cursor has 0 rows. Very handy for
        // "if there's anything to look at, look at it" conditionals.
        if (cursor != null && cursor.moveToFirst()) {

            // Note it's called "Display Name". This is
            // provider-specific, and might not necessarily be the file name.
            String displayName = cursor.getString(
                    cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
            Log.i(TAG, "Display Name: " + displayName);

            int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
            // If the size is unknown, the value stored is null. But because an
            // int can't be null, the behavior is implementation-specific,
            // and unpredictable. So as
            // a rule, check if it's null before assigning to an int. This will
            // happen often: The storage API allows for remote files, whose
            // size might not be locally known.
            String size = null;
            if (!cursor.isNull(sizeIndex)) {
                // Technically the column stores an int, but cursor.getString()
                // will do the conversion automatically.
                size = cursor.getString(sizeIndex);
            } else {
                size = "Unknown";
            }
            Log.i(TAG, "Size: " + size);
        }
    } finally {
        cursor.close();
    }
}

একটি নথি খুলুন

একটি নথির URI-তে একটি রেফারেন্স থাকার মাধ্যমে, আপনি আরও প্রক্রিয়াকরণের জন্য একটি নথি খুলতে পারেন৷ এই বিভাগটি একটি বিটম্যাপ এবং একটি ইনপুট স্ট্রীম খোলার উদাহরণ দেখায়।

বিটম্যাপ

নিম্নলিখিত কোড স্নিপেট দেখায় কিভাবে একটি Bitmap ফাইল খুলতে হয় তার URI দেওয়া হয়:

কোটলিন

val contentResolver = applicationContext.contentResolver

@Throws(IOException::class)
private fun getBitmapFromUri(uri: Uri): Bitmap {
    val parcelFileDescriptor: ParcelFileDescriptor =
            contentResolver.openFileDescriptor(uri, "r")
    val fileDescriptor: FileDescriptor = parcelFileDescriptor.fileDescriptor
    val image: Bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor)
    parcelFileDescriptor.close()
    return image
}

জাভা

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

আপনি বিটম্যাপ খোলার পরে, আপনি এটি একটি ImageView এ প্রদর্শন করতে পারেন।

ইনপুট স্ট্রিম

নিম্নলিখিত কোড স্নিপেটটি দেখায় যে কীভাবে একটি ইনপুটস্ট্রিম অবজেক্ট খুলতে হয় তার URI দেওয়া হয়৷ এই স্নিপেটে, ফাইলের লাইনগুলি একটি স্ট্রিংয়ে পড়া হচ্ছে:

কোটলিন

val contentResolver = applicationContext.contentResolver

@Throws(IOException::class)
private fun readTextFromUri(uri: Uri): String {
    val stringBuilder = StringBuilder()
    contentResolver.openInputStream(uri)?.use { inputStream ->
        BufferedReader(InputStreamReader(inputStream)).use { reader ->
            var line: String? = reader.readLine()
            while (line != null) {
                stringBuilder.append(line)
                line = reader.readLine()
            }
        }
    }
    return stringBuilder.toString()
}

জাভা

private String readTextFromUri(Uri uri) throws IOException {
    StringBuilder stringBuilder = new StringBuilder();
    try (InputStream inputStream =
            getContentResolver().openInputStream(uri);
            BufferedReader reader = new BufferedReader(
            new InputStreamReader(Objects.requireNonNull(inputStream)))) {
        String line;
        while ((line = reader.readLine()) != null) {
            stringBuilder.append(line);
        }
    }
    return stringBuilder.toString();
}

একটি নথি সম্পাদনা করুন

আপনি জায়গায় একটি পাঠ্য নথি সম্পাদনা করতে স্টোরেজ অ্যাক্সেস ফ্রেমওয়ার্ক ব্যবহার করতে পারেন।

নিম্নলিখিত কোড স্নিপেট প্রদত্ত ইউআরআই দ্বারা উপস্থাপিত নথির বিষয়বস্তু ওভাররাইট করে:

কোটলিন

val contentResolver = applicationContext.contentResolver

private fun alterDocument(uri: Uri) {
    try {
        contentResolver.openFileDescriptor(uri, "w")?.use {
            FileOutputStream(it.fileDescriptor).use {
                it.write(
                    ("Overwritten at ${System.currentTimeMillis()}\n")
                        .toByteArray()
                )
            }
        }
    } catch (e: FileNotFoundException) {
        e.printStackTrace()
    } catch (e: IOException) {
        e.printStackTrace()
    }
}

জাভা

private void alterDocument(Uri uri) {
    try {
        ParcelFileDescriptor pfd = getActivity().getContentResolver().
                openFileDescriptor(uri, "w");
        FileOutputStream fileOutputStream =
                new FileOutputStream(pfd.getFileDescriptor());
        fileOutputStream.write(("Overwritten at " + System.currentTimeMillis() +
                "\n").getBytes());
        // Let the document provider know you're done by closing the stream.
        fileOutputStream.close();
        pfd.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

একটি নথি মুছুন

যদি আপনার কাছে একটি নথির জন্য URI থাকে এবং নথির Document.COLUMN_FLAGS SUPPORTS_DELETE উদাহরণ স্বরূপ:

কোটলিন

DocumentsContract.deleteDocument(applicationContext.contentResolver, uri)

জাভা

DocumentsContract.deleteDocument(applicationContext.contentResolver, uri);

একটি সমতুল্য মিডিয়া URI পুনরুদ্ধার করুন

getMediaUri() পদ্ধতি একটি মিডিয়া স্টোর URI প্রদান করে যা প্রদত্ত নথি প্রদানকারী URI-এর সমতুল্য। 2টি ইউআরআই একই অন্তর্নিহিত আইটেমকে নির্দেশ করে। মিডিয়া স্টোর ইউআরআই ব্যবহার করে, আপনি শেয়ার করা স্টোরেজ থেকে মিডিয়া ফাইলগুলিকে আরও সহজে অ্যাক্সেস করতে পারেন৷

getMediaUri() পদ্ধতিটি ExternalStorageProvider URI-কে সমর্থন করে। Android 12 (API স্তর 31) এবং উচ্চতর, পদ্ধতিটি MediaDocumentsProvider URI-কে সমর্থন করে।

একটি ভার্চুয়াল ফাইল খুলুন

Android 7.0 (API স্তর 25) এবং উচ্চতর সংস্করণে, আপনার অ্যাপ ভার্চুয়াল ফাইলগুলি ব্যবহার করতে পারে যা স্টোরেজ অ্যাক্সেস ফ্রেমওয়ার্ক উপলব্ধ করে। যদিও ভার্চুয়াল ফাইলগুলির একটি বাইনারি উপস্থাপনা নেই, আপনার অ্যাপ তাদের বিষয়বস্তুগুলিকে একটি ভিন্ন ফাইলের ধরনে জোর করে বা ACTION_VIEW অভিপ্রায় ক্রিয়া ব্যবহার করে সেই ফাইলগুলি দেখার মাধ্যমে খুলতে পারে৷

ভার্চুয়াল ফাইলগুলি খুলতে, আপনার ক্লায়েন্ট অ্যাপকে সেগুলি পরিচালনা করার জন্য বিশেষ যুক্তি অন্তর্ভুক্ত করতে হবে। আপনি যদি ফাইলটির একটি বাইট উপস্থাপনা পেতে চান - ফাইলটির পূর্বরূপ দেখতে, উদাহরণস্বরূপ - আপনাকে নথি প্রদানকারীর থেকে একটি বিকল্প MIME প্রকারের জন্য অনুরোধ করতে হবে৷

ব্যবহারকারী একটি নির্বাচন করার পরে, ফাইলটি ভার্চুয়াল কিনা তা নির্ধারণ করতে ফলাফলের ডেটাতে URI ব্যবহার করুন, যেমনটি নিম্নলিখিত কোড স্নিপেটে দেখানো হয়েছে:

কোটলিন

private fun isVirtualFile(uri: Uri): Boolean {
    if (!DocumentsContract.isDocumentUri(this, uri)) {
        return false
    }

    val cursor: Cursor? = contentResolver.query(
            uri,
            arrayOf(DocumentsContract.Document.COLUMN_FLAGS),
            null,
            null,
            null
    )

    val flags: Int = cursor?.use {
        if (cursor.moveToFirst()) {
            cursor.getInt(0)
        } else {
            0
        }
    } ?: 0

    return flags and DocumentsContract.Document.FLAG_VIRTUAL_DOCUMENT != 0
}

জাভা

private boolean isVirtualFile(Uri uri) {
    if (!DocumentsContract.isDocumentUri(this, uri)) {
        return false;
    }

    Cursor cursor = getContentResolver().query(
        uri,
        new String[] { DocumentsContract.Document.COLUMN_FLAGS },
        null, null, null);

    int flags = 0;
    if (cursor.moveToFirst()) {
        flags = cursor.getInt(0);
    }
    cursor.close();

    return (flags & DocumentsContract.Document.FLAG_VIRTUAL_DOCUMENT) != 0;
}

ডকুমেন্টটি একটি ভার্চুয়াল ফাইল তা আপনি যাচাই করার পরে, আপনি ফাইলটিকে একটি বিকল্প MIME প্রকারে বাধ্য করতে পারেন, যেমন "image/png" । নিম্নলিখিত কোড স্নিপেট দেখায় যে কীভাবে একটি ভার্চুয়াল ফাইলকে চিত্র হিসাবে উপস্থাপন করা যায় কিনা তা পরীক্ষা করতে হয় এবং যদি তাই হয়, ভার্চুয়াল ফাইল থেকে একটি ইনপুট স্ট্রীম পায়:

কোটলিন

@Throws(IOException::class)
private fun getInputStreamForVirtualFile(
        uri: Uri, mimeTypeFilter: String): InputStream {

    val openableMimeTypes: Array<String>? =
            contentResolver.getStreamTypes(uri, mimeTypeFilter)

    return if (openableMimeTypes?.isNotEmpty() == true) {
        contentResolver
                .openTypedAssetFileDescriptor(uri, openableMimeTypes[0], null)
                .createInputStream()
    } else {
        throw FileNotFoundException()
    }
}

জাভা

private InputStream getInputStreamForVirtualFile(Uri uri, String mimeTypeFilter)
    throws IOException {

    ContentResolver resolver = getContentResolver();

    String[] openableMimeTypes = resolver.getStreamTypes(uri, mimeTypeFilter);

    if (openableMimeTypes == null ||
        openableMimeTypes.length < 1) {
        throw new FileNotFoundException();
    }

    return resolver
        .openTypedAssetFileDescriptor(uri, openableMimeTypes[0], null)
        .createInputStream();
}

অতিরিক্ত সম্পদ

কীভাবে নথি এবং অন্যান্য ফাইলগুলি সংরক্ষণ এবং অ্যাক্সেস করতে হয় সে সম্পর্কে আরও তথ্যের জন্য, নিম্নলিখিত সংস্থানগুলি দেখুন৷

নমুনা

ভিডিও