In vielen Fällen erstellt Ihre App Dateien, auf die andere Apps nicht zugreifen müssen oder sollten. Das System bietet die folgenden Speicherorte zum Speichern solcher app-spezifischen Dateien:
Verzeichnisse für internen Speicher:Diese Verzeichnisse umfassen sowohl einen dedizierten Speicherort für persistente Dateien als auch einen weiteren Speicherort für Cache-Daten. Das System verhindert, dass andere Apps auf diese Speicherorte zugreifen. Unter Android 10 (API‑Level 29) und höher werden diese Speicherorte verschlüsselt. Diese Eigenschaften machen diese Speicherorte zu einem guten Ort zum Speichern vertraulicher Daten, auf die nur Ihre App selbst zugreifen kann.
Externe Speicherverzeichnisse:Diese Verzeichnisse umfassen sowohl einen dedizierten Speicherort für persistente Dateien als auch einen weiteren Speicherort für Cache-Daten. Obwohl andere Apps mit den entsprechenden Berechtigungen auf diese Verzeichnisse zugreifen können, sind die darin gespeicherten Dateien nur für die Verwendung durch Ihre App vorgesehen. Wenn Sie Dateien erstellen möchten, auf die andere Apps zugreifen können, sollte Ihre App diese Dateien stattdessen im gemeinsamen Speicher des externen Speichers speichern.
Wenn der Nutzer Ihre App deinstalliert, werden die im app-spezifischen Speicher gespeicherten Dateien entfernt. Aus diesem Grund sollten Sie diesen Speicher nicht verwenden, um Inhalte zu speichern, die der Nutzer unabhängig von Ihrer App behalten möchte. Wenn Ihre App beispielsweise Nutzern ermöglicht, Fotos aufzunehmen, erwarten sie, dass sie auch nach der Deinstallation Ihrer App auf diese Fotos zugreifen können. Sie sollten daher stattdessen den freigegebenen Speicher verwenden, um diese Arten von Dateien in der entsprechenden Mediensammlung zu speichern.
In den folgenden Abschnitten wird beschrieben, wie Sie Dateien in appspezifischen Verzeichnissen speichern und darauf zugreifen.
Zugriff über den internen Speicher
Für jede App stellt das System Verzeichnisse im internen Speicher bereit, in denen eine App ihre Dateien organisieren kann. Ein Verzeichnis ist für die persistenten Dateien Ihrer App vorgesehen und ein anderes enthält die im Cache gespeicherten Dateien Ihrer App. Ihre App benötigt keine Systemberechtigungen, um Dateien in diesen Verzeichnissen zu lesen und zu schreiben.
Andere Apps können nicht auf Dateien zugreifen, die im internen Speicher gespeichert sind. Daher ist der interne Speicher ein guter Ort für App-Daten, auf die andere Apps nicht zugreifen sollten.
Diese Verzeichnisse sind jedoch in der Regel klein. Bevor Ihre App app-spezifische Dateien in den internen Speicher schreibt, sollte sie den freien Speicherplatz auf dem Gerät abfragen.
Auf persistente Dateien zugreifen
Die normalen, persistenten Dateien Ihrer App befinden sich in einem Verzeichnis, auf das Sie mit dem Attribut filesDir
eines Kontextobjekts zugreifen können. Das Framework bietet mehrere Methoden, mit denen Sie auf Dateien in diesem Verzeichnis zugreifen und sie dort speichern können.
Auf Dateien zugreifen und Dateien speichern
Mit der File
API können Sie auf Dateien zugreifen und sie speichern.
Um die Leistung Ihrer App zu erhalten, sollten Sie dieselbe Datei nicht mehrmals öffnen und schließen.
Das folgende Code-Snippet zeigt, wie die File
API verwendet wird:
Kotlin
val file = File(context.filesDir, filename)
Java
File file = new File(context.getFilesDir(), filename);
Datei über einen Stream speichern
Alternativ zur Verwendung der File
API können Sie openFileOutput()
aufrufen, um ein FileOutputStream
zu erhalten, das in eine Datei im Verzeichnis filesDir
schreibt.
Das folgende Code-Snippet zeigt, wie Sie Text in eine Datei schreiben:
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()); }
Wenn Sie anderen Apps den Zugriff auf Dateien erlauben möchten, die in diesem Verzeichnis im internen Speicher gespeichert sind, verwenden Sie ein FileProvider
mit dem Attribut FLAG_GRANT_READ_URI_PERMISSION
.
Über einen Stream auf eine Datei zugreifen
Um eine Datei als Stream zu lesen, verwenden Sie 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(); }
Dateiliste ansehen
Sie können ein Array mit den Namen aller Dateien im Verzeichnis filesDir
abrufen, indem Sie fileList()
aufrufen, wie im folgenden Code-Snippet gezeigt:
Kotlin
var files: Array<String> = context.fileList()
Java
Array<String> files = context.fileList();
Verschachtelte Verzeichnisse erstellen
Sie können auch verschachtelte Verzeichnisse erstellen oder ein inneres Verzeichnis öffnen, indem Sie getDir()
in Kotlin-basiertem Code aufrufen oder das Stammverzeichnis und einen neuen Verzeichnisnamen an einen File
-Konstruktor in Java-basiertem Code übergeben:
Kotlin
context.getDir(dirName, Context.MODE_PRIVATE)
Java
File directory = context.getFilesDir(); File file = new File(directory, filename);
Cache-Dateien erstellen
Wenn Sie vertrauliche Daten nur vorübergehend speichern müssen, sollten Sie das dafür vorgesehene Cache-Verzeichnis der App im internen Speicher verwenden. Wie bei allen app-spezifischen Speichern werden die in diesem Verzeichnis gespeicherten Dateien entfernt, wenn der Nutzer Ihre App deinstalliert. Die Dateien in diesem Verzeichnis werden jedoch möglicherweise früher entfernt.
Rufen Sie File.createTempFile()
auf, um eine Datei im Cache zu erstellen:
Kotlin
File.createTempFile(filename, null, context.cacheDir)
Java
File.createTempFile(filename, null, context.getCacheDir());
Ihre App greift über die Eigenschaft cacheDir
eines Kontextobjekts und die API File
auf eine Datei in diesem Verzeichnis zu:
Kotlin
val cacheFile = File(context.cacheDir, filename)
Java
File cacheFile = new File(context.getCacheDir(), filename);
Cache-Dateien entfernen
Auch wenn Android manchmal Cache-Dateien von selbst löscht, sollten Sie sich nicht darauf verlassen, dass das System diese Dateien für Sie bereinigt. Die Cache-Dateien Ihrer App sollten immer im internen Speicher abgelegt werden.
Wenn Sie eine Datei aus dem Cacheverzeichnis im internen Speicher entfernen möchten, haben Sie folgende Möglichkeiten:
Die Methode
delete()
für einFile
-Objekt, das die Datei darstellt:Kotlin
cacheFile.delete()
Java
cacheFile.delete();
Die Methode
deleteFile()
des App-Kontexts, wobei der Name der Datei übergeben wird:Kotlin
context.deleteFile(cacheFileName)
Java
context.deleteFile(cacheFileName);
Zugriff über externen Speicher
Wenn der interne Speicher nicht genügend Speicherplatz für app-spezifische Dateien bietet, sollten Sie stattdessen den externen Speicher verwenden. Das System stellt Verzeichnisse im externen Speicher bereit, in denen eine App Dateien organisieren kann, die nur innerhalb Ihrer App für den Nutzer von Nutzen sind. Ein Verzeichnis ist für die persistenten Dateien Ihrer App vorgesehen, ein anderes enthält die im Cache gespeicherten Dateien Ihrer App.
Unter Android 4.4 (API-Level 19) oder höher muss Ihre App keine speicherbezogenen Berechtigungen anfordern, um auf appspezifische Verzeichnisse auf dem externen Speicher zuzugreifen. Die in diesen Verzeichnissen gespeicherten Dateien werden entfernt, wenn Ihre App deinstalliert wird.
Auf Geräten mit Android 9 (API‑Level 28) oder niedriger kann Ihre App auf die app-spezifischen Dateien anderer Apps zugreifen, sofern sie die entsprechenden Speicherberechtigungen hat. Damit Nutzer mehr Kontrolle über ihre Dateien haben und weniger Dateien auf dem Gerät gespeichert werden, erhalten Apps, die für Android 10 (API-Level 29) und höher entwickelt wurden, standardmäßig einen eingeschränkten Zugriff auf den externen Speicher, auch Scoped Storage genannt. Wenn der bereichsbezogene Speicher aktiviert ist, können Apps nicht auf die app-spezifischen Verzeichnisse anderer Apps zugreifen.
Verfügbarkeit von Speicherplatz prüfen
Da sich der externe Speicher auf einem physischen Volume befindet, das der Nutzer möglicherweise entfernen kann, müssen Sie prüfen, ob das Volume zugänglich ist, bevor Sie versuchen, app-spezifische Daten aus dem externen Speicher zu lesen oder in den externen Speicher zu schreiben.
Sie können den Status des Volumes abfragen, indem Sie Environment.getExternalStorageState()
aufrufen.
Wenn der zurückgegebene Status MEDIA_MOUNTED
ist, können Sie appspezifische Dateien auf dem externen Speicher lesen und schreiben. Wenn es MEDIA_MOUNTED_READ_ONLY
ist, können Sie diese Dateien nur lesen.
Die folgenden Methoden sind beispielsweise nützlich, um die Speicherverfügbarkeit zu ermitteln:
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); }
Verwenden Sie auf Geräten ohne herausnehmbaren externen Speicher den folgenden Befehl, um ein virtuelles Volume zum Testen der Logik für die Verfügbarkeit des externen Speichers zu aktivieren:
adb shell sm set-virtual-disk true
Physischen Speicherort auswählen
Manchmal verfügt ein Gerät, das einen Teil seines internen Speichers als externen Speicher zuweist, auch über einen SD-Kartensteckplatz. Das bedeutet, dass das Gerät mehrere physische Volumes hat, die externen Speicher enthalten können. Sie müssen also auswählen, welches für den app-spezifischen Speicher verwendet werden soll.
Rufen Sie ContextCompat.getExternalFilesDirs()
auf, um auf die verschiedenen Standorte zuzugreifen.
Wie im Code-Snippet zu sehen ist, gilt das erste Element im zurückgegebenen Array als primäres externes Speichermedium. Verwende dieses Volume, sofern es nicht voll oder nicht verfügbar ist.
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];
Auf persistente Dateien zugreifen
Wenn Sie über den externen Speicher auf app-spezifische Dateien zugreifen möchten, rufen Sie getExternalFilesDir()
auf.
Um die Leistung Ihrer App zu erhalten, sollten Sie dieselbe Datei nicht mehrmals öffnen und schließen.
Das folgende Code-Snippet zeigt, wie getExternalFilesDir()
aufgerufen wird:
Kotlin
val appSpecificExternalDir = File(context.getExternalFilesDir(null), filename)
Java
File appSpecificExternalDir = new File(context.getExternalFilesDir(null), filename);
Cache-Dateien erstellen
Wenn Sie dem Cache im externen Speicher eine app-spezifische Datei hinzufügen möchten, rufen Sie eine Referenz auf externalCacheDir
ab:
Kotlin
val externalCacheFile = File(context.externalCacheDir, filename)
Java
File externalCacheFile = new File(context.getExternalCacheDir(), filename);
Cache-Dateien entfernen
Wenn Sie eine Datei aus dem externen Cacheverzeichnis entfernen möchten, verwenden Sie die Methode delete()
für ein File
-Objekt, das die Datei darstellt:
Kotlin
externalCacheFile.delete()
Java
externalCacheFile.delete();
Medieninhalte
Wenn Ihre App mit Mediendateien arbeitet, die dem Nutzer nur innerhalb Ihrer App einen Mehrwert bieten, sollten Sie sie in app-spezifischen Verzeichnissen im externen Speicher speichern, wie im folgenden Code-Snippet gezeigt:
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; }
Es ist wichtig, dass Sie Verzeichnisnamen verwenden, die von API-Konstanten wie DIRECTORY_PICTURES
bereitgestellt werden.
Diese Verzeichnisnamen sorgen dafür, dass die Dateien vom System richtig behandelt werden.
Wenn keiner der vordefinierten Unterverzeichnisnamen für Ihre Dateien geeignet ist, können Sie stattdessen null
an getExternalFilesDir()
übergeben. Dadurch wird das anwendungsspezifische Stammverzeichnis im externen Speicher zurückgegeben.
Freien Speicherplatz abfragen
Viele Nutzer haben nicht viel Speicherplatz auf ihren Geräten. Daher sollte Ihre App nur so viel Speicherplatz wie nötig belegen.
Wenn Sie im Voraus wissen, wie viele Daten Sie speichern, können Sie mit dem Aufruf von getAllocatableBytes()
herausfinden, wie viel Speicherplatz das Gerät Ihrer App zur Verfügung stellen kann.
Der Rückgabewert von getAllocatableBytes()
kann größer sein als der aktuelle kostenlose Speicherplatz auf dem Gerät. Das liegt daran, dass das System Dateien gefunden hat, die aus den Cache-Verzeichnissen anderer Apps entfernt werden können.
Wenn genügend Speicherplatz zum Speichern der Daten Ihrer App vorhanden ist, rufen Sie allocateBytes()
auf.
Andernfalls kann Ihre App den Nutzer auffordern, einige Dateien oder alle Cache-Dateien vom Gerät zu entfernen.
Das folgende Code-Snippet zeigt ein Beispiel dafür, wie Ihre App den freien Speicherplatz auf dem Gerät abfragen kann:
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); }
Speicherverwaltungsaktivität erstellen
Ihre App kann eine benutzerdefinierte Aktivität deklarieren und erstellen, die beim Starten dem Nutzer ermöglicht, die Daten zu verwalten, die Ihre App auf dem Gerät des Nutzers gespeichert hat. Sie deklarieren diese benutzerdefinierte Aktivität „manage space“ mit dem Attribut android:manageSpaceActivity
in der Manifestdatei. Dateimanager-Apps können diese Aktivität aufrufen, auch wenn Ihre App die Aktivität nicht exportiert, d. h., wenn für Ihre Aktivität android:exported
auf false
festgelegt ist.
Nutzer bitten, einige Gerätedateien zu entfernen
Wenn Sie den Nutzer auffordern möchten, Dateien auf dem Gerät auszuwählen, die entfernt werden sollen, rufen Sie einen Intent auf, der die Aktion ACTION_MANAGE_STORAGE
enthält. Bei diesem Intent wird dem Nutzer ein Prompt angezeigt. Auf Wunsch kann in diesem Hinweis der auf dem Gerät verfügbare kostenlose Speicherplatz angezeigt werden. Um diese nutzerfreundlichen Informationen anzuzeigen, verwenden Sie das Ergebnis der folgenden Berechnung:
StorageStatsManager.getFreeBytes() / StorageStatsManager.getTotalBytes()
Nutzer bitten, alle Cache-Dateien zu entfernen
Alternativ können Sie den Nutzer bitten, die Cache-Dateien aller Apps auf dem Gerät zu löschen. Rufen Sie dazu einen Intent auf, der die Intent-Aktion ACTION_CLEAR_APP_CACHE
enthält.
Zusätzliche Ressourcen
Weitere Informationen zum Speichern von Dateien auf dem Gerätespeicher finden Sie in den folgenden Ressourcen.