במקרים רבים, האפליקציה יוצרת קבצים שאפליקציות אחרות לא צריכות גישה אליהם, או שאין להן גישה אליהם. המערכת מספקת את המיקומים הבאים לאחסון קבצים ספציפיים לאפליקציה:
ספריות אחסון פנימי: הספריות האלה כוללות גם מיקום ייעודי לאחסון קבצים קבועים וגם מיקום אחר לאחסון נתוני מטמון. המערכת מונעת מאפליקציות אחרות לגשת למיקומים האלה, וב-Android 10 (רמת API 29) ואילך המיקומים האלה מוצפנים. המאפיינים האלה הופכים את המיקומים האלה למקום טוב לאחסון מידע רגיש שרק לאפליקציה עצמה יש גישה אליו.
ספריות אחסון חיצוניות: הספריות האלה כוללות גם מיקום ייעודי לאחסון קבצים קבועים וגם מיקום אחר לאחסון נתוני מטמון. למרות שלאפליקציה אחרת יש אפשרות לגשת לספריות האלה אם לאפליקציה יש את ההרשאות המתאימות, הקבצים שמאוחסנים בספריות האלו מיועדים לשימוש של האפליקציה בלבד. אם אתם מתכוונים באופן ספציפי ליצור קבצים שאפליקציות אחרות יוכלו לגשת אליהם, האפליקציה צריכה לאחסן אותם בחלק האחסון המשותף של האחסון החיצוני.
כשהמשתמש מסיר את האפליקציה, הקבצים שנשמרו באחסון הייעודי לאפליקציה יוסרו. בגלל ההתנהגות הזו, לא מומלץ להשתמש באחסון הזה כדי לשמור פריטים שהמשתמשים מצפים שיישמרו בנפרד מהאפליקציה. לדוגמה, אם האפליקציה מאפשרת למשתמשים לצלם תמונות, הם מצפים שתהיה להם גישה לתמונות האלה גם אחרי שהם מסירים את האפליקציה. לכן, במקום זאת, כדאי להשתמש באחסון המשותף כדי לשמור את סוגי הקבצים האלה באוסף המדיה המתאים.
בקטעים הבאים מוסבר איך לאחסן קבצים בתוך ספריות ספציפיות לאפליקציה ולגשת אליהם.
גישה מהאחסון הפנימי
לכל אפליקציה, המערכת מספקת ספריות באחסון הפנימי שבהן האפליקציה יכולה לארגן את הקבצים שלה. ספרייה אחת מיועדת לקבצים הקבועים של האפליקציה, וספרייה אחרת מכילה את הקבצים ששמורים במטמון של האפליקציה. לאפליקציה שלכם לא נדרשות הרשאות מערכת כדי לקרוא ולכתוב בקבצים בספריות האלה.
אפליקציות אחרות לא יכולות לגשת לקבצים שמאוחסנים באחסון הפנימי. לכן, האחסון הפנימי הוא מקום טוב לשמירת נתוני אפליקציות שאפליקציות אחרות לא צריכות לגשת אליהם.
עם זאת, חשוב לזכור שהספריות האלה בדרך כלל קטנות. לפני שכותבים קבצים ספציפיים לאפליקציה באחסון הפנימי, צריך לבצע שאילתה על שטח האחסון הפנוי במכשיר.
גישה לקבצים קבועים
הקבצים הקבועים והרגילים של האפליקציה נמצאים בספרייה שניתן לגשת אליה באמצעות המאפיין filesDir
של אובייקט ההקשר. ה-framework מספק מספר שיטות שיעזרו לכם לגשת לקבצים בספרייה הזו ולאחסן אותם.
גישה לאחסון קבצים
אפשר להשתמש ב-API של File
כדי לגשת לקבצים ולאחסן אותם.
כדי לשמור על הביצועים של האפליקציה, מומלץ לא לפתוח ולסגור את אותו הקובץ כמה פעמים.
קטע הקוד הבא מדגים איך משתמשים ב-API של File
:
Kotlin
val file = File(context.filesDir, filename)
Java
File file = new File(context.getFilesDir(), filename);
אחסון קובץ באמצעות סטרימינג
לחלופין, אפשר להפעיל את openFileOutput()
כדי לקבל FileOutputStream
שכותב לקובץ בספרייה filesDir
.File
קטע הקוד הבא מראה איך לכתוב טקסט בקובץ:
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, או על ידי העברת ספריית הבסיס ושם ספרייה חדש ל-constructor 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
של אובייקט ההקשר ו-API 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);
גישה מאחסון חיצוני
אם אין מספיק מקום באחסון הפנימי לאחסון קבצים ספציפיים לאפליקציה, מומלץ להשתמש באחסון חיצוני במקום זאת. המערכת מספקת ספריות באחסון חיצוני שבהן האפליקציה יכולה לארגן את הקבצים שמספקים ערך למשתמש רק בתוך האפליקציה. ספרייה אחת מיועדת לקבצים הקבועים של האפליקציה וספרייה אחרת מכילה את הקבצים ששמורים במטמון של האפליקציה.
ב-Android 4.4 (רמת API 19) ואילך, האפליקציה לא צריכה לבקש הרשאות שקשורות לאחסון כדי לגשת לספריות ספציפיות לאפליקציה באחסון החיצוני. הקבצים שמאוחסנים בספריות האלה יוסרו כשהאפליקציה תוסר.
במכשירים עם Android 9 (רמת API 28) ומטה, האפליקציה יכולה לגשת לקבצים הספציפיים של האפליקציה ששייכים לאפליקציות אחרות, בתנאי שיש לאפליקציה את הרשאות האחסון המתאימות. כדי לתת למשתמשים יותר שליטה על הקבצים שלהם ולהגביל את העומס של הקבצים, אפליקציות שמטרגטות את Android מגרסה 10 ואילך (רמת API 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; }
חשוב להשתמש בשמות ספריות שמסופקים על ידי קבועים של API, כמו 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
.
לבקש מהמשתמש להסיר קבצים מסוימים מהמכשיר
כדי לבקש מהמשתמש לבחור קבצים במכשיר להסרה, מפעילים כוונה שכוללת את הפעולה ACTION_MANAGE_STORAGE
. ההגדרה של Intent זו מציגה הנחיה למשתמש. אם תרצו, תוכלו להציג בהנחיה הזו את שטח האחסון הפנוי במכשיר. כדי להציג את המידע הזה בצורה ידידותית למשתמש, צריך להשתמש בתוצאה של החישוב הבא:
StorageStatsManager.getFreeBytes() / StorageStatsManager.getTotalBytes()
לבקש מהמשתמש להסיר את כל קובצי המטמון
לחלופין, אפשר לבקש מהמשתמש לנקות את קובצי המטמון מכל האפליקציות במכשיר. כדי לעשות זאת, מפעילים כוונה שכוללת את פעולת הכוונה ACTION_CLEAR_APP_CACHE
.
מקורות מידע נוספים
למידע נוסף על שמירת קבצים באחסון של המכשיר, תוכלו לעיין במקורות המידע הבאים.