Çoğu durumda, uygulamanız diğer uygulamaların erişmesi gerekmeyen veya erişememesi gereken dosyalar oluşturur. Sistem, bu tür uygulamaya özel dosyaların depolanması için aşağıdaki konumları sağlar:
Dahili depolama dizinleri: Bu dizinler hem kalıcı dosyaları depolamak için özel bir konum hem de önbellek verilerini depolamak için başka bir konum içerir. Sistem, diğer uygulamaların bu konumlara erişmesini önler ve Android 10 (API düzeyi 29) ve sonraki sürümlerde bu konumlar şifrelenir. Bu özellikler, söz konusu konumları yalnızca uygulamanızın erişebileceği hassas verileri depolamak için iyi bir yer haline getirir.
Harici depolama dizinleri: Bu dizinler, hem kalıcı dosyaları depolamak için özel bir konum hem de önbellek verilerini depolamak için başka bir konum içerir. Uygun izinlere sahip başka bir uygulama bu dizinlere erişebilir ancak bu dizinlerde depolanan dosyalar, yalnızca uygulamanız tarafından kullanılmak üzere tasarlanmıştır. Özellikle diğer uygulamaların erişebilmesi gereken dosyalar oluşturmak istiyorsanız, uygulamanız bu dosyaları harici depolama alanının paylaşılan depolama bölümünde depolamalıdır.
Kullanıcı uygulamanızı kaldırdığında, uygulamaya özel depolama alanına kaydedilen dosyalar kaldırılır. Bu nedenle, bu depolama alanını, kullanıcıların uygulamanızdan bağımsız olarak sürdürmek istedikleri şeyleri kaydetmek için kullanmamalısınız. Örneğin, uygulamanız kullanıcıların fotoğraf çekmesine izin veriyorsa, kullanıcılar uygulamanızı kaldırdıktan sonra bile bu fotoğraflara erişebilmelerini beklerler. Bu nedenle, bu tür dosyaları uygun medya koleksiyonuna kaydetmek için paylaşılan depolama alanını kullanmalısınız.
Aşağıdaki bölümlerde, uygulamaya özel dizinlerdeki dosyaların nasıl saklanacağı ve bu dosyalara nasıl erişileceği açıklanmaktadır.
Dahili depolama alanından erişim
Sistem, her uygulama için dahili depolama alanında, uygulamanın dosyalarını düzenleyebileceği dizinler sağlar. Bir dizin uygulamanızın kalıcı dosyaları için tasarlanmıştır, diğeri ise uygulamanızın önbelleğe alınan dosyalarını içerir. Uygulamanız bu dizinlerdeki dosyaları okumak ve bu dosyalara yazmak için sistem izinlerine ihtiyaç duymuyor.
Diğer uygulamalar, dahili depolamada depolanan dosyalara erişemez. Bu, dahili depolamayı diğer uygulamaların erişmemesi gereken uygulama verileri için iyi bir yer haline getirir.
Ancak, bu dizinlerin küçük olma eğiliminde olduğunu unutmayın. Uygulamaya özel dosyaları dahili depolama alanına yazmadan önce uygulamanızın cihazdaki boş alanı sorgulaması gerekir.
Kalıcı dosyalara erişme
Uygulamanızın normal, kalıcı dosyaları, bağlam nesnesinin filesDir
özelliğini kullanarak erişebileceğiniz bir dizinde bulunur. Çerçeve, bu dizindeki dosyalara erişmenize ve bunları depolamanıza yardımcı olacak çeşitli yöntemler sunar.
Dosyalara erişme ve dosyaları depolama
Dosyalara erişmek ve bunları depolamak için File
API'yi kullanabilirsiniz.
Uygulamanızın performansını korumaya yardımcı olmak için aynı dosyayı birden çok kez açıp kapatmayın.
Aşağıdaki kod snippet'i, File
API'nin nasıl kullanılacağını gösterir:
Kotlin
val file = File(context.filesDir, filename)
Java
File file = new File(context.getFilesDir(), filename);
Akış kullanarak dosya depolama
File
API'nin kullanılmasına alternatif olarak, filesDir
dizini içindeki bir dosyaya yazan bir FileOutputStream
almak için openFileOutput()
yöntemini çağırabilirsiniz.
Aşağıdaki kod snippet'inde bir dosyaya nasıl metin yazılacağı gösterilmektedir:
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()); }
Dahili depolama alanında bu dizinde depolanan diğer uygulamaların dosyalara erişmesine izin vermek için FLAG_GRANT_READ_URI_PERMISSION
özelliğine sahip bir FileProvider
kullanın.
Dosyaya akış kullanarak erişme
Bir dosyayı akış olarak okumak için openFileInput()
öğesini kullanın:
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(); }
Dosya listesini göster
Aşağıdaki kod snippet'inde gösterildiği gibi, fileList()
yöntemini çağırarak filesDir
dizinindeki tüm dosyaların adlarını içeren bir dizi alabilirsiniz:
Kotlin
var files: Array<String> = context.fileList()
Java
Array<String> files = context.fileList();
İç içe dizinler oluşturma
Ayrıca Kotlin tabanlı kodda getDir()
çağrısı yaparak ya da kök dizin ve yeni dizin adını Java tabanlı kodda bir File
oluşturucuya ileterek iç içe dizinler oluşturabilir veya iç dizin açabilirsiniz:
Kotlin
context.getDir(dirName, Context.MODE_PRIVATE)
Java
File directory = context.getFilesDir(); File file = new File(directory, filename);
Önbellek dosyaları oluşturma
Hassas verileri yalnızca geçici olarak depolamanız gerekiyorsa verileri kaydetmek için dahili depolamada uygulamanın özel önbellek dizinini kullanmanız gerekir. Uygulamaya özel tüm depolama alanlarında olduğu gibi, kullanıcı uygulamanızı kaldırdığında bu dizinde depolanan dosyalar da kaldırılır ancak bu dizindeki dosyalar daha erken kaldırılabilir.
Önbelleğe alınan bir dosya oluşturmak için File.createTempFile()
çağrısı yapın:
Kotlin
File.createTempFile(filename, null, context.cacheDir)
Java
File.createTempFile(filename, null, context.getCacheDir());
Uygulamanız, bir bağlam nesnesinin cacheDir
özelliğini ve File
API'sini kullanarak bu dizindeki bir dosyaya erişir:
Kotlin
val cacheFile = File(context.cacheDir, filename)
Java
File cacheFile = new File(context.getCacheDir(), filename);
Önbellek dosyalarını kaldırma
Android bazen önbellek dosyalarını kendi başına siler, ancak bu dosyaları sizin için temizlemesi için sisteme güvenmemelisiniz. Uygulamanızın önbellek dosyalarını her zaman dahili depolamada saklamalısınız.
Bir dosyayı dahili depolama içindeki önbellek dizininden kaldırmak için aşağıdaki yöntemlerden birini kullanın:
Dosyayı temsil eden bir
File
nesnesindedelete()
yöntemi:Kotlin
cacheFile.delete()
Java
cacheFile.delete();
Dosyanın adını ileten uygulama bağlamı için
deleteFile()
yöntemi:Kotlin
context.deleteFile(cacheFileName)
Java
context.deleteFile(cacheFileName);
Harici depolama alanından erişim
Dahili depolama, uygulamaya özel dosyaları depolamak için yeterli alan sağlamıyorsa bunun yerine harici depolama kullanmayı düşünebilirsiniz. Sistem, uygulamaların kullanıcıya yalnızca uygulamanızın içinde değer sağlayan dosyaları düzenleyebileceği harici depolama alanında dizinler sağlar. Dizinlerden biri uygulamanızın kalıcı dosyaları için tasarlanmıştır, diğeri ise uygulamanızın önbelleğe aldığı dosyaları içerir.
Uygulamanızın, Android 4.4 (API düzeyi 19) veya sonraki sürümlerde harici depolama alanındaki uygulamaya özel dizinlere erişmek için depolama alanıyla ilgili herhangi bir izin istemesine gerek yoktur. Bu dizinlerde depolanan dosyalar, uygulamanız kaldırıldığında kaldırılır.
Uygulamanız, Android 9 (API düzeyi 28) veya önceki sürümleri çalıştıran cihazlarda uygun depolama izinlerine sahip olduğu sürece diğer uygulamalara ait uygulamaya özel dosyalara erişebilir. Kullanıcılara dosyaları üzerinde daha fazla kontrol sağlamak ve dosya dağınıklığını sınırlamak için Android 10 (API düzeyi 29) ve üst sürümlerini hedefleyen uygulamalara varsayılan olarak harici depolamaya veya kapsamlı depolamaya kapsamlı erişim verilir. Kapsamlı depolama etkinleştirildiğinde, uygulamalar diğer uygulamalara ait olan uygulamaya özel dizinlere erişemez.
Depolama alanının kullanılabilir olduğunu doğrulama
Harici depolama, kullanıcının kaldırabileceği fiziksel bir birimde bulunduğundan, harici depolama biriminden uygulamaya özel verileri okumaya veya uygulamaya özel verileri yazmaya çalışmadan önce birime erişilebildiğini doğrulayın.
Environment.getExternalStorageState()
numaralı telefonu arayarak birimin durumunu sorgulayabilirsiniz.
Döndürülen durum MEDIA_MOUNTED
ise harici depolama alanındaki uygulamaya özel dosyaları okuyup yazabilirsiniz. MEDIA_MOUNTED_READ_ONLY
olarak ayarlanmışsa bu dosyaları yalnızca okuyabilirsiniz.
Örneğin, aşağıdaki yöntemler depolama alanı kullanılabilirliğinin belirlenmesinde yararlıdır:
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); }
Çıkarılabilir harici depolama alanı bulunmayan cihazlarda, harici depolama kullanılabilirliği mantığınızı test etmek üzere bir sanal birimi etkinleştirmek için aşağıdaki komutu kullanın:
adb shell sm set-virtual-disk true
Fiziksel depolama konumu seçin
Bazen, dahili belleğinin bir bölümünü harici depolama olarak ayıran bir cihaz, aynı zamanda bir SD kart yuvası da sağlar. Yani, cihazda harici depolama içerebilecek birden fazla fiziksel birim vardır. Bu nedenle, uygulamaya özel depolama alanınız için hangisinin kullanılacağını seçmeniz gerekir.
Farklı konumlara erişmek için ContextCompat.getExternalFilesDirs()
numaralı telefonu arayın.
Kod snippet'inde gösterildiği gibi, döndürülen dizideki ilk öğe birincil harici depolama birimi olarak kabul edilir. Dolu değilse veya kullanılamadığı sürece
bu cildi kullanın.
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];
Kalıcı dosyalara erişme
Harici depolama alanından uygulamaya özel dosyalara erişmek için getExternalFilesDir()
numaralı telefonu arayın.
Uygulamanızın performansını korumaya yardımcı olmak için aynı dosyayı birden çok kez açıp kapatmayın.
Aşağıdaki kod snippet'inde getExternalFilesDir()
çağrısının nasıl yapılacağı gösterilmektedir:
Kotlin
val appSpecificExternalDir = File(context.getExternalFilesDir(null), filename)
Java
File appSpecificExternalDir = new File(context.getExternalFilesDir(null), filename);
Önbellek dosyaları oluşturma
Harici depolama alanındaki önbelleğe uygulamaya özel bir dosya eklemek için externalCacheDir
referansına bakın:
Kotlin
val externalCacheFile = File(context.externalCacheDir, filename)
Java
File externalCacheFile = new File(context.getExternalCacheDir(), filename);
Önbellek dosyalarını kaldırma
Bir dosyayı harici önbellek dizininden kaldırmak için dosyayı temsil eden bir File
nesnesinde delete()
yöntemini kullanın:
Kotlin
externalCacheFile.delete()
Java
externalCacheFile.delete();
Medya içeriği
Uygulamanız kullanıcıya yalnızca uygulamanızın içinde değer sağlayan medya dosyalarıyla çalışıyorsa bunları aşağıdaki kod snippet'inde gösterildiği gibi harici depolama alanındaki uygulamaya özel dizinlerde saklamak en iyisidir:
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
gibi API sabit değerleri tarafından sağlanan dizin adlarını kullanmanız önemlidir.
Bu dizin adları, dosyaların sistem tarafından doğru bir şekilde ele alınmasını sağlar.
Önceden tanımlanmış alt dizin adlarından hiçbiri dosyalarınıza uymuyorsa bunun yerine null
öğesini getExternalFilesDir()
öğesine iletebilirsiniz. Bu komut, harici depolama alanındaki kök uygulamaya özel dizini döndürür.
Boş alan sorgulama
Birçok kullanıcının cihazlarında yeterli depolama alanı olmadığından uygulamanız alanı dikkatli bir şekilde tüketmelidir.
Ne kadar veri depoladığınızı önceden biliyorsanız getAllocatableBytes()
numaralı telefonu arayarak cihazın uygulamanıza ne kadar yer açabileceğini öğrenebilirsiniz.
Döndürülen getAllocatableBytes()
değeri, cihazdaki mevcut boş alan miktarından daha büyük olabilir. Bunun nedeni, sistemin, diğer uygulamaların önbellek dizinlerinden kaldırabileceği dosyaları tanımlamış olmasıdır.
Uygulamanızın verilerini kaydetmek için yeterli alan varsa allocateBytes()
numaralı telefonu arayın.
Aksi takdirde, uygulamanız kullanıcıdan bazı dosyaları veya cihazdan tüm önbellek dosyalarını kaldırmasını isteyebilir.
Aşağıdaki kod snippet'i, uygulamanızın cihazdaki boş alanı nasıl sorgulayabileceğine dair bir örnek gösterir:
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); }
Depolama alanı yönetim etkinliği oluşturma
Uygulamanız, başlatıldığında kullanıcının cihazında depoladığı verileri yönetmesine olanak tanıyan özel bir etkinlik tanımlayıp oluşturabilir. Bu özel "alanı yönetme" etkinliğini, manifest dosyasındaki android:manageSpaceActivity
özelliğini kullanarak beyan edersiniz. Dosya yöneticisi uygulamaları, uygulamanız etkinliği dışa aktarmadığında (yani etkinliğiniz android:exported
değerini false
olarak ayarladığında) bile bu etkinliği çağırabilir.
Kullanıcıdan bazı cihaz dosyalarını kaldırmasını isteyin
Kullanıcının cihazdaki kaldırılacak dosyaları seçmesini istemek için ACTION_MANAGE_STORAGE
işlemini içeren bir amaç çağırın. Bu intent, kullanıcıya bir istem gösterir. İstenirse bu istem cihazdaki kullanılabilir boş alan miktarını gösterebilir. Kullanıcı dostu bu bilgiyi göstermek için aşağıdaki hesaplama sonucunu kullanın:
StorageStatsManager.getFreeBytes() / StorageStatsManager.getTotalBytes()
Kullanıcıdan tüm önbellek dosyalarını kaldırmasını iste
Alternatif olarak, kullanıcıdan önbellek dosyalarını cihazdaki tüm uygulamalardan temizlemesini isteyebilirsiniz. Bunu yapmak için ACTION_CLEAR_APP_CACHE
amaç işlemini içeren bir amaç çağırın.
Ek kaynaklar
Dosyaları cihazın depolama alanına kaydetme hakkında daha fazla bilgi için aşağıdaki kaynaklara bakın.