Dostęp do plików związanych z aplikacją

Często aplikacja tworzy pliki, z których inne aplikacje nie potrzebują dostępu. nie powinny uzyskać dostępu. System udostępnia następujące lokalizacje przechowywania takich danych specyficzne dla aplikacji:

  • Katalogi pamięci wewnętrznej: te katalogi zawierają zarówno specjalne, miejsce przechowywania plików trwałych i inna lokalizacja do ich przechowywania. dane z pamięci podręcznej. system blokuje innym aplikacjom dostęp do tych lokalizacji, na Androidzie 10 (poziom interfejsu API 29) i nowszych te lokalizacje są zaszyfrowane. Te że te lokalizacje są dobrym miejscem do przechowywania danych wrażliwych, ma dostęp tylko Twoja aplikacja.

  • Zewnętrzne katalogi pamięci masowej: tego typu katalogi zawierają zarówno miejsce przechowywania plików trwałych i inna lokalizacja do ich przechowywania. dane z pamięci podręcznej. Inna aplikacja może uzyskać dostęp do tych katalogów jeśli aplikacja ma odpowiednie uprawnienia, pliki przechowywane w tych katalogach są przeznaczone wyłącznie na potrzeby aplikacji. Jeśli zamierzasz utworzyć pliki do których inne aplikacje powinny mieć dostęp, aplikacja powinna zapisywać te pliki w część pamięci współdzielonej w pamięci zewnętrznej .

Gdy użytkownik odinstaluje Twoją aplikację, pliki zapisane w pamięci aplikacji zostaną usunięto. Z tego powodu nie należy korzystać z tego miejsca, aby oszczędzać wszystkie elementy, które użytkownik chce zachować niezależnie od aplikacji. Dla: na przykład jeśli aplikacja umożliwia robienie zdjęć, użytkownik powinien oczekiwać, użytkownicy będą mieli dostęp do tych zdjęć nawet po odinstalowaniu aplikacji. Dlatego korzystają z pamięci współdzielonej, aby zapisywać tego typu pliki w odpowiednich zbierania multimediów.

W poniższych sekcjach opisano, jak przechowywać pliki i uzyskać do nich dostęp w obrębie katalogów aplikacji.

Dostęp z pamięci wewnętrznej

Dla każdej aplikacji system udostępnia w pamięci wewnętrznej katalogi, w których może porządkować pliki. Jeden katalog jest przeznaczony na potrzeby plików trwałych, a drugi – plik cookie aplikacji plików z pamięci podręcznej. Aplikacja nie wymaga żadnego systemu uprawnień do odczytu i zapisu w plikach w tych katalogach.

Inne aplikacje nie mogą uzyskać dostępu do plików przechowywanych w pamięci wewnętrznej. Dzięki temu to dobre miejsce na dane aplikacji, do których inne aplikacje nie powinny mieć dostępu.

Pamiętaj jednak, że te katalogi są zwykle małe. Przed napisaniem plików do pamięci wewnętrznej, aplikacja powinna wysyłać zapytania do bezpłatnej miejsca na urządzeniu.

Dostęp do plików trwałych

Zwykłe, trwałe pliki aplikacji znajdują się w katalogu, uzyskać dostęp za pomocą funkcji filesDir właściwości obiektu kontekstu. Ten schemat udostępnia kilka metod, które pomagają dostępu do plików i przechowywania ich w tym katalogu.

uzyskiwać dostęp do plików i przechowywać je

Interfejsu API File możesz używać do uzyskiwania dostępu do plików i ich przechowywania.

Aby aplikacja działała wydajnie, nie otwieraj jej i nie zamykaj wiele razy.

Ten fragment kodu pokazuje, jak korzystać z interfejsu API File:

Kotlin

val file = File(context.filesDir, filename)

Java

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

Przechowywanie pliku za pomocą strumienia

Zamiast używać interfejsu API File, możesz wywołać openFileOutput(). aby uzyskać FileOutputStream, który zapisuje do pliku w katalogu filesDir.

Ten fragment kodu pokazuje, jak zapisać tekst w pliku:

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

Aby zezwolić innym aplikacjom na dostęp do plików przechowywanych na w tym katalogu w pamięci wewnętrznej, użyj funkcji FileProvider z FLAG_GRANT_READ_URI_PERMISSION. .

Uzyskiwanie dostępu do pliku przy użyciu strumienia

Aby odczytać plik jako strumień, użyj 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();
}

Wyświetl listę plików

Można uzyskać tablicę zawierającą nazwy wszystkich plików w funkcji filesDir katalogu, wywołując fileList(), jak widać tutaj ten fragment kodu:

Kotlin

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

Java

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

Tworzenie katalogów zagnieżdżonych

Możesz też utworzyć katalogi zagnieżdżone lub otworzyć wewnętrzny katalog przez wywołanie getDir() w języku Kotlin lub przez przekazanie katalogu głównego i nowej nazwy katalogu do pliku File konstruktora w kodzie w Javie:

Kotlin

context.getDir(dirName, Context.MODE_PRIVATE)

Java

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

Tworzenie plików pamięci podręcznej

Jeśli chcesz przechowywać dane wrażliwe tylko tymczasowo, użyj w wyznaczonym katalogu pamięci podręcznej w pamięci wewnętrznej, gdzie zostaną zapisane dane. Podobnie jak dla całej pamięci aplikacji, pliki przechowywane w tym katalogu są usuwane, gdy użytkownik odinstaluje aplikację, mimo że pliki w tym katalogu mogą zostać usunięte wcześniej.

Aby utworzyć plik z pamięci podręcznej, wywołaj File.createTempFile():

Kotlin

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

Java

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

Aplikacja uzyskuje dostęp do pliku w tym katalogu za pomocą funkcji Właściwość cacheDir elementu obiekt kontekstu i interfejs API File:

Kotlin

val cacheFile = File(context.cacheDir, filename)

Java

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

Usuń pliki z pamięci podręcznej

Mimo że Android czasami sam usuwa pliki pamięci podręcznej, nie należy polegać w systemie, by wyczyścić te pliki. Zawsze należy dbać o i pliki z pamięcią podręczną aplikacji w pamięci wewnętrznej.

Aby usunąć plik z katalogu pamięci podręcznej w pamięci wewnętrznej, użyj jednej z tych metod: następujące metody:

  • Metoda delete() na obiekcie File reprezentujący plik:

    Kotlin

    cacheFile.delete()
    

    Java

    cacheFile.delete();
    
  • deleteFile() metody kontekstu aplikacji, przekazując nazwę pliku:

    Kotlin

    context.deleteFile(cacheFileName)
    

    Java

    context.deleteFile(cacheFileName);
    

Dostęp z pamięci zewnętrznej

Jeśli w pamięci wewnętrznej nie ma dość miejsca do przechowywania plików aplikacji, rozważ użycie pamięci zewnętrznej. System udostępnia katalogi w obrębie pamięć zewnętrzna, w której aplikacja może organizować pliki, które są wartościowe dla użytkownika tylko w Twojej aplikacji. Jeden katalog jest przeznaczony dla trwałego , a drugi zawiera pliki Twojej aplikacji w pamięci podręcznej .

Na Androidzie 4.4 (poziom interfejsu API 19) lub nowszym aplikacja nie musi żądać żadnych uprawnienia związane z pamięcią i dostęp do katalogów aplikacji w zewnętrznych pamięci masowej. Pliki przechowywane w tych katalogach są usuwane, gdy aplikacja zostanie Odinstalowano.

Na urządzeniach z Androidem 9 (poziom interfejsu API 28) lub niższym aplikacja może uzyskać dostęp do plików związanych z innymi aplikacjami, które należą do innych aplikacji, jeśli aplikacja ma uprawnienia odpowiednich uprawnień do przechowywania danych. Aby zapewnić użytkownikom większą kontrolę nad ich plikami aby ograniczyć bałagan w plikach, aplikacje kierowane na Androida 10 (poziom API 29) i nowsze ograniczony dostęp do pamięci zewnętrznej lub pamięci masowej. Po zawężeniu pamięć urządzenia jest włączona, aplikacje nie mają dostępu do należących do nich katalogów aplikacji do innych aplikacji.

Sprawdzanie, czy miejsce na dane jest dostępne

Ponieważ pamięć zewnętrzna znajduje się na woluminie fizycznym, którym może być użytkownik możesz usunąć, zanim spróbujesz odczytać, czy wolumin jest dostępny dane aplikacji z pamięci zewnętrznej i zapisywanie w niej danych.

Możesz zapytać o stan woluminu, wywołując Environment.getExternalStorageState() Jeśli zwracany stan to MEDIA_MOUNTED, a potem możesz odczytywać i zapisywać pliki aplikacji w pamięci zewnętrznej. Jeśli jest MEDIA_MOUNTED_READ_ONLY, możesz tylko odczytywać te pliki.

Na przykład poniższe metody są przydatne do określenia ilości miejsca na dane. dostępność:

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

Na urządzeniach bez wymiennej pamięci zewnętrznej użyj tego polecenia, aby włącz wolumin wirtualny na potrzeby testowania logiki dostępności pamięci zewnętrznej:

adb shell sm set-virtual-disk true

Wybierz fizyczną lokalizację pamięci masowej

Czasami urządzenie, które przydziela partycję swojej pamięci wewnętrznej jako a pamięć zewnętrzna ma także gniazdo na kartę SD. Oznacza to, że na urządzeniu wiele woluminów fizycznych, które mogą zawierać pamięć zewnętrzną, dlatego wybierz, który z nich ma być używany do przechowywania danych aplikacji.

Aby uzyskać dostęp do różnych lokalizacji, zadzwoń pod numer ContextCompat.getExternalFilesDirs() Jak widać we fragmencie kodu, pierwszym elementem zwróconej tablicy jest jest uznawany za główną pamięć zewnętrzną. Używaj tej głośności, chyba że będzie pełna lub niedostępna.

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

Dostęp do plików trwałych

Aby uzyskać dostęp do plików aplikacji z pamięci zewnętrznej, zadzwoń pod numer getExternalFilesDir()

Aby aplikacja działała wydajnie, nie otwieraj jej i nie zamykaj wiele razy.

Ten fragment kodu pokazuje, jak wywołać funkcję getExternalFilesDir():

Kotlin

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

Java

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

Tworzenie plików pamięci podręcznej

Aby dodać plik aplikacji do pamięci podręcznej w pamięci zewnętrznej, pobierz odwołanie do externalCacheDir:

Kotlin

val externalCacheFile = File(context.externalCacheDir, filename)

Java

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

Usuń pliki z pamięci podręcznej

Aby usunąć plik z katalogu zewnętrznej pamięci podręcznej, użyj delete() na obiekcie File, który reprezentuje plik:

Kotlin

externalCacheFile.delete()

Java

externalCacheFile.delete();

Treści multimedialne

Jeśli Twoja aplikacja obsługuje pliki multimedialne, które są wartościowe dla użytkownika tylko w aplikacji, najlepiej przechowywać je w katalogach zewnętrznych jak w poniższym fragmencie kodu:

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

Ważne jest, aby używać nazw katalogów dostarczanych przez stałe interfejsu API, takie jak DIRECTORY_PICTURES Nazwy katalogów zapewniają prawidłowe traktowanie plików przez system. Jeśli żaden ze wstępnie zdefiniowanych podkatalogów nazwy pasują do Twoich plików, zamiast tego przekazać null do getExternalFilesDir(). Powoduje to zwrócenie pierwiastka katalog aplikacji w pamięci zewnętrznej.

Zapytanie o wolne miejsce

Wielu użytkowników nie ma zbyt dużo miejsca na swoich urządzeniach, dlatego Twoja aplikacja i starannie je wykorzystywać.

Jeśli wiesz z góry, ile danych przechowujesz, możesz dowiedzieć się dużo miejsca, które urządzenie może zapewnić aplikacji przez połączenie telefoniczne getAllocatableBytes() Wartość zwrócona przez funkcję getAllocatableBytes() może być większa niż bieżąca i ilość wolnego miejsca w pamięci urządzenia. Dzieje się tak, ponieważ system zidentyfikował które może usunąć z innych aplikacji katalogu pamięci podręcznej.

Jeśli jest wystarczająco dużo miejsca na zapisanie danych aplikacji, wywołaj allocateBytes() W przeciwnym razie aplikacja może poprosić użytkownika o usunięcie niektórych pliki z urządzenia lub wyczyść całą pamięć podręczną z urządzenia.

Ten fragment kodu pokazuje, jak aplikacja może wysyłać zapytania o wolne miejsce na urządzeniu:

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

Tworzenie aktywności związanej z zarządzaniem miejscem na dane

Aplikacja może zadeklarować i utworzyć niestandardową aktywność, która po uruchomieniu umożliwia do zarządzania danymi przechowywanymi przez aplikację na urządzeniu użytkownika. Ty zadeklaruj ten niestandardowy „zarządzaj obszarem” za pomocą android:manageSpaceActivity w pliku manifestu. Aplikacje menedżera plików mogą wywołać takie działanie aktywność nawet jeśli aplikacja jej nie eksportuje; czyli kiedy aktywność ustawia się android:exported na false.

Poproś użytkownika o usunięcie niektórych plików z urządzenia

Aby poprosić użytkownika o wybranie plików na urządzeniu do usunięcia, wywołaj intencję obejmujący ACTION_MANAGE_STORAGE działania. Ta intencja wyświetla prompt dla użytkownika. W razie potrzeby ten prompt może pokazuje ilość wolnego miejsca dostępnego w urządzeniu. Pokazuj przyjaznych dla użytkownika informacji, należy zastosować następujący wynik obliczeń:

StorageStatsManager.getFreeBytes() / StorageStatsManager.getTotalBytes()

Poproś użytkownika o usunięcie wszystkich plików z pamięci podręcznej

Możesz też poprosić użytkownika o wyczyszczenie plików pamięci podręcznej wszystkich aplikacje na urządzeniu. Aby to zrobić, wywołaj intencję zawierającą ACTION_CLEAR_APP_CACHE działanie intencji.

Dodatkowe materiały

Więcej informacji o zapisywaniu plików w pamięci urządzenia znajdziesz w poniższe zasoby.

Filmy