الوصول إلى الملفات الخاصة بالتطبيقات

في كثير من الحالات، ينشئ تطبيقك ملفات لا تحتاج التطبيقات الأخرى إلى الوصول إليها، أو الوصول إليها. يوفر النظام المواقع التالية لتخزين الخاصة بالتطبيقات:

  • أدلة وحدة التخزين الداخلية: تتضمن هذه الأدلّة كلاً من مجلد ومكان لتخزين الملفات الدائمة، وموقع آخر لتخزين بيانات ذاكرة التخزين المؤقت. يمنع النظام التطبيقات الأخرى من الوصول إلى هذه المواقع الجغرافية يتم تشفير هذه المواقع الجغرافية على نظام التشغيل Android 10 (مستوى واجهة برمجة التطبيقات 29) والإصدارات الأحدث. هذه وخصائصها تجعل هذه المواقع مكانًا جيدًا لتخزين البيانات الحساسة التي لا يمكن الوصول إليه سوى للتطبيق نفسه.

  • أدلة مساحة التخزين الخارجية: تتضمن هذه الأدلّة كلاً من مجلد ومكان لتخزين الملفات الدائمة، وموقع آخر لتخزين بيانات ذاكرة التخزين المؤقت. رغم أنه من الممكن لتطبيق آخر الوصول إلى هذه الأدلة إذا كان هذا التطبيق لديه الأذونات المناسبة، فإن الملفات المخزنة في هذه الأدلة مصمّمة للاستخدام بواسطة تطبيقك فقط. إذا كنت تنوي إنشاء ملفات على وجه التحديد التي ينبغي أن تتمكن التطبيقات الأخرى من الوصول إليها، فيجب أن يخزن التطبيق هذه الملفات في جزء مساحة التخزين المشتركة من وحدة التخزين الخارجية بدلاً من ذلك.

عندما يلغي المستخدم تثبيت تطبيقك، يتم تخزين الملفات المحفوظة في مساحة التخزين الخاصة بالتطبيق. تمت إزالته. بسبب هذا السلوك، يجب عدم استخدام مساحة التخزين هذه لتوفير أي شيء يتوقع المستخدم استمراره بشكل مستقل عن تطبيقك. بالنسبة على سبيل المثال، إذا كان تطبيقك يسمح للمستخدمين بالتقاط الصور، يتوقّع المستخدم أن يمكنهم الوصول إلى تلك الصور حتى بعد إلغاء تثبيت التطبيق. لذلك ينبغي أن وبدلاً من ذلك، يمكنك استخدام مساحة التخزين المشتركة لحفظ هذه الأنواع من الملفات في المجلد جمع الوسائط

توضح الأقسام التالية كيفية تخزين الملفات والوصول إليها داخل الأدلة الخاصة بالتطبيقات.

الوصول من وحدة التخزين الداخلية

بالنسبة إلى كل تطبيق، يوفر النظام أدلة داخل وحدة التخزين الداخلية حيث التطبيق تنظيم ملفاته. تم تصميم دليل واحد لـ وملفات دائمة، ويحتوي عنوان آخر على من الملفات المخزَّنة مؤقتًا. لا يتطلّب تطبيقك أي نظام. الأذونات بالقراءة والكتابة إلى الملفات في هذه الأدلة.

ولا يمكن للتطبيقات الأخرى الوصول إلى الملفات المخزنة داخل وحدة التخزين الداخلية. وهذا يجعل وحدة التخزين الداخلية مكان جيد لبيانات التطبيقات التي لا ينبغي للتطبيقات الأخرى الوصول إليها.

ومع ذلك، ضع في اعتبارك أن هذه الأدلة تميل إلى أن تكون صغيرة. قبل الكتابة ملفات خاصة بالتطبيق إلى وحدة التخزين الداخلية، يجب على التطبيق البحث في المساحة على الجهاز.

الوصول إلى الملفات الدائمة

تتوفّر الملفات العادية والدائمة لتطبيقك في دليل يمكنك الوصول باستخدام filesDir خاصية كائن السياق. يوفر إطار العمل العديد من الطرق لمساعدتك الوصول إلى الملفات وتخزينها في هذا الدليل.

الوصول إلى الملفات وتخزينها

يمكنك استخدام واجهة برمجة تطبيقات File للوصول إلى الملفات وتخزينها.

للمساعدة في الحفاظ على أداء تطبيقك، لا تفتحه أو تغلقه. الملف عدة مرات.

يوضّح مقتطف الرمز التالي طريقة استخدام واجهة برمجة تطبيقات File:

Kotlin

val file = File(context.filesDir, filename)

Java

File file = new File(context.getFilesDir(), filename);

تخزين ملف باستخدام ساحة مشاركات

كبديل لاستخدام واجهة برمجة تطبيقات File، يمكنك طلب openFileOutput() للحصول على FileOutputStream تكتب إلى ملف داخل دليل filesDir.

يوضح مقتطف الرمز التالي كيفية كتابة نص إلى ملف:

Kotlin

val filename = "myfile"
val fileContents = "Hello world!"
context.openFileOutput(filename, Context.MODE_PRIVATE).use {
        it.write(fileContents.toByteArray())
}

Java

String filename = "myfile";
String fileContents = "Hello world!";
try (FileOutputStream fos = context.openFileOutput(filename, Context.MODE_PRIVATE)) {
    fos.write(fileContents.toByteArray());
}

للسماح للتطبيقات الأخرى بالوصول إلى الملفات المخزَّنة في هذا الدليل في وحدة التخزين الداخلية، استخدم FileProvider مع FLAG_GRANT_READ_URI_PERMISSION .

الوصول إلى ملف باستخدام مصدر بيانات

لقراءة ملف في صورة مصدر بيانات، استخدم openFileInput():

Kotlin

context.openFileInput(filename).bufferedReader().useLines { lines ->
    lines.fold("") { some, text ->
        "$some\n$text"
    }
}

Java

FileInputStream fis = context.openFileInput(filename);
InputStreamReader inputStreamReader =
        new InputStreamReader(fis, StandardCharsets.UTF_8);
StringBuilder stringBuilder = new StringBuilder();
try (BufferedReader reader = new BufferedReader(inputStreamReader)) {
    String line = reader.readLine();
    while (line != null) {
        stringBuilder.append(line).append('\n');
        line = reader.readLine();
    }
} catch (IOException e) {
    // Error occurred when opening raw file for reading.
} finally {
    String contents = stringBuilder.toString();
}

عرض قائمة الملفات

يمكنك الحصول على مصفوفة تحتوي على أسماء جميع الملفات داخل filesDir. الدليل من خلال طلب fileList()، كما هو موضّح في مقتطف الرمز التالي:

Kotlin

var files: Array<String> = context.fileList()

Java

Array<String> files = context.fileList();

إنشاء أدلة متداخلة

يمكنك أيضًا إنشاء أدلة متداخلة أو فتح دليل داخلي من خلال استدعاء getDir() المستندة إلى لغة البرمجة Kotlin الرمز أو عن طريق إدخال الدليل الجذر واسم دليل جديد إلى File الدالة الإنشائية في تعليمة برمجية تستند إلى Java:

Kotlin

context.getDir(dirName, Context.MODE_PRIVATE)

Java

File directory = context.getFilesDir();
File file = new File(directory, filename);

إنشاء ملفات ذاكرة تخزين مؤقت

إذا كنت بحاجة إلى تخزين البيانات الحساسة بشكل مؤقت فقط، فيجب عليك استخدام دليل ذاكرة التخزين المؤقت المعين في وحدة التخزين الداخلية لحفظ البيانات. وكما هي الحال في في حالة كل سعة التخزين الخاصة بالتطبيقات، فإن الملفات المخزنة في هذا الدليل تتم إزالتها عندما يلغي المستخدم تثبيت تطبيقك، على الرغم من أنّ الملفات في هذا الدليل قد تتم إزالتها في وقت أقرب.

لإنشاء ملف مخزَّن مؤقتًا، اتصل File.createTempFile():

Kotlin

File.createTempFile(filename, null, context.cacheDir)

Java

File.createTempFile(filename, null, context.getCacheDir());

يصل تطبيقك إلى ملف في هذا الدليل باستخدام السمة cacheDir كائن السياق وFile واجهة برمجة التطبيقات:

Kotlin

val cacheFile = File(context.cacheDir, filename)

Java

File cacheFile = new File(context.getCacheDir(), filename);

إزالة ملفات ذاكرة التخزين المؤقت

رغم أنّ Android يحذف أحيانًا ملفات ذاكرة التخزين المؤقت تلقائيًا، يجب ألا تعتمد على النظام تنظيف هذه الملفات نيابة عنك. يجب عليك دائمًا الحفاظ على ملفات ذاكرة التخزين المؤقت للتطبيق في وحدة التخزين الداخلية.

لإزالة ملف من دليل ذاكرة التخزين المؤقت في وحدة التخزين الداخلية، استخدم أحد الطرق التالية:

  • الطريقة delete() في كائن File يمثل الملف:

    Kotlin

    cacheFile.delete()
    

    Java

    cacheFile.delete();
    
  • تشير رسالة الأشكال البيانية deleteFile() لسياق التطبيق، وتمرير اسم الملف:

    Kotlin

    context.deleteFile(cacheFileName)
    

    Java

    context.deleteFile(cacheFileName);
    

الوصول من وحدة التخزين الخارجية

إذا لم توفر وحدة التخزين الداخلية مساحة كافية لتخزين الملفات الخاصة بالتطبيق، ففكر في استخدام وحدة تخزين خارجية بدلاً من ذلك. يوفر النظام أدلة داخل وحدة تخزين خارجية حيث يمكن للتطبيق تنظيم الملفات التي تقدم قيمة للمستخدم داخل تطبيقك فقط. تمّ تصميم دليل واحد لمستخدمي تطبيقك الدائم ، ويحتوي جدول آخر على ذاكرة التخزين المؤقت لتطبيقك .

في الإصدار 4.4 من نظام التشغيل Android (المستوى 19 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، لن يحتاج تطبيقك إلى طلب أي الأذونات المتعلقة بمساحة التخزين للوصول إلى الأدلة الخاصة بالتطبيق داخل الملفات الخارجية مساحة التخزين. تتم إزالة الملفات المخزنة في هذه الأدلة عندما يكون تطبيقك تمت إزالته.

على الأجهزة التي تعمل بنظام التشغيل Android 9 (المستوى 28 من واجهة برمجة التطبيقات) أو الإصدارات الأقدم، يمكن لتطبيقك الوصول إلى الملفات الخاصة بالتطبيق التي تنتمي إلى تطبيقات أخرى، بشرط أن يتوفر للتطبيق أذونات التخزين المناسبة. لمنح المستخدمين مزيدًا من التحكم في ملفاتهم للحدّ من فوضى الملفات، سيتم منح التطبيقات التي تستهدف Android 10 (المستوى 29 من واجهة برمجة التطبيقات) والإصدارات الأحدث أو وصول محدد إلى وحدة التخزين الخارجية أو نطاق مساحة التخزين تلقائيًا. عند تحديد النطاق تم تفعيل مساحة التخزين، لا يمكن للتطبيقات الوصول إلى الأدلة الخاصة بالتطبيقات بالتطبيقات الأخرى.

التأكّد من توفّر مساحة التخزين

لأنّ وحدة التخزين الخارجية تكمن في وحدة تخزين ما قد يكون المستخدم قادرًا على إزالته، والتحقق من أنه يمكن الوصول إلى مستوى الصوت قبل محاولة القراءة البيانات الخاصة بالتطبيق من وحدة التخزين الخارجية أو كتابة بيانات خاصة بالتطبيق إليها

يمكنك الاستعلام عن حالة مستوى الصوت من خلال استدعاء Environment.getExternalStorageState() إذا كانت الحالة التي تم إرجاعها MEDIA_MOUNTED، ثم يمكنك قراءة وكتابة ملفات خاصة بالتطبيق داخل وحدة التخزين الخارجية. إذا كان MEDIA_MOUNTED_READ_ONLY، يمكنك قراءة هذه الملفات فقط.

فعلى سبيل المثال، تكون الطرق التالية مفيدة لتحديد سعة التخزين مدى التوفّر:

Kotlin

// Checks if a volume containing external storage is available
// for read and write.
fun isExternalStorageWritable(): Boolean {
    return Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED
}

// Checks if a volume containing external storage is available to at least read.
fun isExternalStorageReadable(): Boolean {
     return Environment.getExternalStorageState() in
        setOf(Environment.MEDIA_MOUNTED, Environment.MEDIA_MOUNTED_READ_ONLY)
}

Java

// Checks if a volume containing external storage is available
// for read and write.
private boolean isExternalStorageWritable() {
    return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
}

// Checks if a volume containing external storage is available to at least read.
private boolean isExternalStorageReadable() {
     return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ||
            Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY);
}

على الأجهزة التي لا تحتوي على وحدة تخزين خارجية قابلة للإزالة، يمكنك استخدام الأمر التالي من أجل: تفعيل وحدة تخزين افتراضية لاختبار منطق مدى توفّر وحدة التخزين الخارجية:

adb shell sm set-virtual-disk true

اختيار مكان تخزين مادي

في بعض الأحيان، يستخدم الجهاز الذي يخصص قسمًا من ذاكرته الداخلية وحدة التخزين الخارجية توفر أيضًا فتحة لبطاقة SD. هذا يعني أن الجهاز يحتوي على وحدات تخزين مادية متعددة يمكن أن تحتوي على وحدة تخزين خارجية، ولذلك تحتاج إلى اختَر الحساب الذي تريد استخدامه للتخزين الخاص بتطبيقك.

للوصول إلى المواقع الجغرافية المختلفة، يُرجى الاتصال ContextCompat.getExternalFilesDirs() كما هو موضح في مقتطف الرمز، يكون العنصر الأول في الصفيف المعروض تعتبر حجم وحدة التخزين الخارجية الأساسية. استخدِم وحدة الصوت هذه ما لم تكن ممتلئة. أو غير متاحة

Kotlin

val externalStorageVolumes: Array<out File> =
        ContextCompat.getExternalFilesDirs(applicationContext, null)
val primaryExternalStorage = externalStorageVolumes[0]

Java

File[] externalStorageVolumes =
        ContextCompat.getExternalFilesDirs(getApplicationContext(), null);
File primaryExternalStorage = externalStorageVolumes[0];

الوصول إلى الملفات الدائمة

للوصول إلى الملفات الخاصة بالتطبيق من وحدة التخزين الخارجية، اتصل getExternalFilesDir()

للمساعدة في الحفاظ على أداء تطبيقك، لا تفتحه أو تغلقه. الملف عدة مرات.

يوضح مقتطف الرمز التالي طريقة طلب البيانات لـ getExternalFilesDir():

Kotlin

val appSpecificExternalDir = File(context.getExternalFilesDir(null), filename)

Java

File appSpecificExternalDir = new File(context.getExternalFilesDir(null), filename);

إنشاء ملفات ذاكرة تخزين مؤقت

لإضافة ملف خاص بالتطبيق إلى ذاكرة التخزين المؤقت داخل وحدة تخزين خارجية، احصل على الإشارة إلى externalCacheDir:

Kotlin

val externalCacheFile = File(context.externalCacheDir, filename)

Java

File externalCacheFile = new File(context.getExternalCacheDir(), filename);

إزالة ملفات ذاكرة التخزين المؤقت

لإزالة ملف من دليل ذاكرة التخزين المؤقت الخارجي، استخدم ملف delete() على كائن File الملف:

Kotlin

externalCacheFile.delete()

Java

externalCacheFile.delete();

محتوى الوسائط

إذا كان تطبيقك يعمل مع ملفات وسائط تقدّم قيمة للمستخدم فقط تطبيقك، فمن الأفضل تخزينها في أدلة خاصة بالتطبيق داخل التخزين، كما هو موضح في مقتطف الرمز التالي:

Kotlin

fun getAppSpecificAlbumStorageDir(context: Context, albumName: String): File? {
    // Get the pictures directory that's inside the app-specific directory on
    // external storage.
    val file = File(context.getExternalFilesDir(
            Environment.DIRECTORY_PICTURES), albumName)
    if (!file?.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created")
    }
    return file
}

Java

@Nullable
File getAppSpecificAlbumStorageDir(Context context, String albumName) {
    // Get the pictures directory that's inside the app-specific directory on
    // external storage.
    File file = new File(context.getExternalFilesDir(
            Environment.DIRECTORY_PICTURES), albumName);
    if (file == null || !file.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;
}

من المهم أن تستخدم أسماء الأدلة التي توفرها ثوابت واجهة برمجة التطبيقات مثل DIRECTORY_PICTURES تضمن أسماء الأدلة هذه التعامل مع الملفات بشكل صحيح من خلال النظام. إذا لم يكن أيًا من الدليل الفرعي المحدد مسبقًا أسماء تناسب ملفاتك، يمكنك تمرير "null" إلى "getExternalFilesDir()" بدلاً من ذلك يُرجع هذا الجذر الدليل الخاص بالتطبيق داخل وحدة التخزين الخارجية.

المساحة الخالية في طلب البحث

لا تتوفّر مساحة تخزين كبيرة على أجهزة العديد من المستخدمين، لذلك يجب أن يستهلك المساحة بعناية.

إذا كنت تعرف مسبقًا مقدار البيانات التي تخزنها، فيمكنك معرفة كيفية المساحة التي يمكن للجهاز توفيرها لتطبيقك من خلال إجراء getAllocatableBytes() قد تكون القيمة المعروضة getAllocatableBytes() أكبر من القيمة الحالية. مقدار المساحة الخالية على الجهاز. وذلك لأن النظام حدد التي يمكنه إزالتها من التطبيقات الأخرى" أدلة ذاكرة التخزين المؤقت.

إذا كانت هناك مساحة كافية لحفظ بيانات التطبيق، يُرجى الاتصال allocateBytes() بخلاف ذلك، يمكن لتطبيقك أن يطلب من المستخدم إزالة بعض البيانات. من الجهاز من الجهاز أو إزالة جميع ذاكرة التخزين المؤقت الملفات من الجهاز.

يعرض مقتطف الرمز التالي مثالاً على كيفية طلب تطبيقك للمساحة الخالية. على الجهاز:

Kotlin

// App needs 10 MB within internal storage.
const val NUM_BYTES_NEEDED_FOR_MY_APP = 1024 * 1024 * 10L;

val storageManager = applicationContext.getSystemService<StorageManager>()!!
val appSpecificInternalDirUuid: UUID = storageManager.getUuidForPath(filesDir)
val availableBytes: Long =
        storageManager.getAllocatableBytes(appSpecificInternalDirUuid)
if (availableBytes >= NUM_BYTES_NEEDED_FOR_MY_APP) {
    storageManager.allocateBytes(
        appSpecificInternalDirUuid, NUM_BYTES_NEEDED_FOR_MY_APP)
} else {
    val storageIntent = Intent().apply {
        // To request that the user remove all app cache files instead, set
        // "action" to ACTION_CLEAR_APP_CACHE.
        action = ACTION_MANAGE_STORAGE
    }
}

Java

// App needs 10 MB within internal storage.
private static final long NUM_BYTES_NEEDED_FOR_MY_APP = 1024 * 1024 * 10L;

StorageManager storageManager =
        getApplicationContext().getSystemService(StorageManager.class);
UUID appSpecificInternalDirUuid = storageManager.getUuidForPath(getFilesDir());
long availableBytes =
        storageManager.getAllocatableBytes(appSpecificInternalDirUuid);
if (availableBytes >= NUM_BYTES_NEEDED_FOR_MY_APP) {
    storageManager.allocateBytes(
            appSpecificInternalDirUuid, NUM_BYTES_NEEDED_FOR_MY_APP);
} else {
    // To request that the user remove all app cache files instead, set
    // "action" to ACTION_CLEAR_APP_CACHE.
    Intent storageIntent = new Intent();
    storageIntent.setAction(ACTION_MANAGE_STORAGE);
}

إنشاء نشاط لإدارة مساحة التخزين

يمكن لتطبيقك الإفصاح عن نشاط مخصَّص يسمح به عند إطلاقه وإنشاءه. للمستخدم إدارة البيانات التي خزنها تطبيقك على جهازه. إِنْتَ إعلان هذا "إدارة المساحة" المخصص النشاط باستخدام android:manageSpaceActivity في ملف البيان. يمكن لتطبيقات إدارة الملفات استدعاء ذلك النشاط حتى في حال عدم تصدير تطبيقك للنشاط أي عندما يضبط نشاطك android:exported إلى false

طلب إزالة بعض الملفات من الجهاز

لمطالبة المستخدم باختيار الملفات الموجودة على الجهاز لإزالته، عليك استدعاء إجراء intent تتضمن ACTION_MANAGE_STORAGE اتخاذ القرار. يعرِض هذا الغرض طلبًا إلى المستخدِم. عند الرغبة في ذلك، يمكن أن لإظهار مقدار المساحة الخالية المتوفرة على الجهاز. لإظهار هذا معلومات سهلة الاستخدام، استخدم نتيجة العملية الحسابية التالية:

StorageStatsManager.getFreeBytes() / StorageStatsManager.getTotalBytes()

طلب إزالة جميع ملفات ذاكرة التخزين المؤقت من المستخدم

بدلاً من ذلك، يمكنك أن تطلب من المستخدم محو ملفات ذاكرة التخزين المؤقت من جميع التطبيقات على الجهاز. وللقيام بذلك، استحضر هدفًا يتضمن ACTION_CLEAR_APP_CACHE الهدف من الإجراء.

مصادر إضافية

لمزيد من المعلومات حول حفظ الملفات في مساحة تخزين الجهاز، يُرجى الرجوع إلى الموارد التالية.

الفيديوهات