---
title: 'Dosya ve Medya Depolama'
source: 'https://academia.sh/tr/kurslar/android-mimari/dosya-ve-medya-depolama'
course: 'Mimari Bileşenler ve Veri Katmanı'
language: tr
updated: '2026-10-21T05:02:37+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Uygulamaya özel dizin ile medya deposunun erişim kurallarını ayırır'
    - 'Kapsamlı depolamanın bir uygulamanın hangi dosyaları görebileceğini sınırladığını açıklar'
    - 'Uygulamaya özel dizindeki dosyanın okumasının kökenini disk olarak ölçer'
    - 'Belleğe alınmış küçük resmin bellek, zincirde olmayan dosyanın varsayılan olduğunu gösterir'
---

# Dosya ve Medya Depolama

Uygulama kendi dizinindeki dosyalara doğrudan, başkalarının medyasına ise medya deposu ve izin kuralları üzerinden erişir. Ders uygulamaya özel dizindeki bir dosyanın okumasının kökenini ve zincire girmeyen dosyanın neye düştüğünü ölçer.

Önceki derste disk basamağı küçük bir tercih mağazasıydı. Uygulama bazen bir fotoğraf, bir belge ya da bir fatura saklar ve bu dosyalar bir satıra ya da tek bir dizgiye sığmaz. Dosyanın nerede durduğu da önemlidir: uygulamanın kendi dizininde mi, yoksa başka uygulamaların da gördüğü ortak bir yerde mi? Dersin sorusu önceki derslerle aynıdır: **bu okumanın yanıtı nereden geliyor?**

```kotlin
// Origin.kt — bir okumanin yanitinin hangi basamaktan geldigini siniflandirir
class Tier(val origin: String, private val entries: Map<String, String>) {
    init {
        require(origin in listOf("bellek", "disk", "ag")) { "gecersiz basamak: $origin" }
    }

    fun lookup(key: String): String? = entries[key]
}

class Read(val label: String, val key: String, chain: List<Tier>, fallback: String) {
    private val hit: Tier? = chain.firstOrNull { it.lookup(key) != null }
    val value: String = hit?.lookup(key) ?: fallback
    val origin: String = hit?.origin ?: "varsayilan"

    fun show() {
        println("$label: anahtar=$key | deger=$value -> $origin")
    }
}

fun countOrigins(reads: List<Read>) {
    for (name in listOf("bellek", "disk", "ag", "varsayilan")) {
        println("$name: ${reads.count { it.origin == name }}")
    }
}
```

## Uygulamaya Özel Dizin

Her uygulamanın platformun verdiği, yalnızca kendisine ait bir dizini vardır. Bu dizin uygulamaya özel dizin (app-specific directory) diye anılır. Uygulama oraya dosya yazmak ve oradan dosya okumak için özel bir izin istemez; başka uygulamalar o dizini göremez. Dizin uygulama silindiğinde de silinir.

```kotlin
// Platform kodu: PrivateFiles
class PrivateFiles(private val context: Context) {
    fun save(name: String, bytes: ByteArray) {
        File(context.filesDir, name).writeBytes(bytes)
    }

    fun read(name: String): ByteArray? {
        val file = File(context.filesDir, name)
        return if (file.exists()) file.readBytes() else null
    }
}
```

`read` dosya yoksa `null` döner; yani bu sınıf da önceki derslerdeki depolar gibi yazılmamış bir şey için yanıt vermez. Bu parça platform kodudur ve burada çıktı, dosya yolu ya da boyut iddia etmiyoruz. Model, platformun bu kuralını kurar; model platformun kendisi değildir.

Modelde dizin, dosya adlarından bir eşlem çıkaran bir işlevdir. Her dosya `dosya.` önekiyle bir anahtara bağlanır; değer, dosyanın dizin içindeki yoludur. Gerçek bir dosya okunmaz ya da yazılmaz.

```kotlin
// Files.kt — bir dizindeki dosya adlarindan anahtar ve yol eslemi cikarir
fun indexDirectory(directory: String, files: List<String>): Map<String, String> =
    files.associate { name -> "dosya.${name.substringBeforeLast('.')}" to "$directory/$name" }
```

Bir ekran üç dosya ister: profil fotoğrafı, fatura ve galeriden seçilmiş bir resim.

```kotlin
// Gallery.kt — dosya ekraninin istedigi uc dosya
fun readFileScreen(chain: List<Tier>): List<Read> = listOf(
    Read("profil", "dosya.profil", chain, "yok"),
    Read("fatura", "dosya.fatura", chain, "yok"),
    Read("galeri", "dosya.galeri", chain, "yok"),
)
```

## Dizindeki Dosya Diskten Gelir

Uygulamanın dizininde iki dosya var: `profil.jpg` ve `fatura.pdf`. Galeri resmi uygulamaya kopyalanmadı.

```kotlin
// Main.kt — uygulamanin kendi dizinindeki dosya diskten okunur
fun main() {
    val privateDir = Tier("disk", indexDirectory("ozel", listOf("profil.jpg", "fatura.pdf")))
    val reads = readFileScreen(listOf(privateDir))
    reads.forEach { it.show() }
    countOrigins(reads)
}
```

```text
profil: anahtar=dosya.profil | deger=ozel/profil.jpg -> disk
fatura: anahtar=dosya.fatura | deger=ozel/fatura.pdf -> disk
galeri: anahtar=dosya.galeri | deger=yok -> varsayilan
bellek: 0
disk: 2
ag: 0
varsayilan: 1
```

İki dosya diskten, galeri resmi yedek değerden geldi. Bu dersin kökeni disktir: uygulamanın dizinindeki bir dosya, disk basamağı tarafından yanıtlanır.

**VK1.** Model, dizini bir ad listesinden türetir ve dosyanın içeriğini taşımaz; değer yalnız yoldur. Platformda dosyanın boyutu, yazılırken yarıda kesilmesi ve disk dolulukla başarısız olması modelde yoktur.

## Medya Deposu ve Kapsamlı Depolama

Galeri resmi uygulamanın dizininde değil, kullanıcının ortak medyasındadır. Platform bu medyaya kapsamlı depolama (scoped storage) kuralıyla erişimi sınırlar: uygulama başka uygulamaların dosyalarını doğrudan yoluyla açamaz. Ortak medyaya, medya deposu (media store) sorgusu üzerinden, kullanıcının verdiği izinle ya da kullanıcının seçtiği dosyayla ulaşır.

```kotlin
// Platform kodu: GalleryQuery
fun queryImageNames(context: Context): List<String> {
    val names = mutableListOf<String>()
    val projection = arrayOf(MediaStore.Images.Media.DISPLAY_NAME)
    context.contentResolver.query(
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null, null, null,
    )?.use { cursor ->
        while (cursor.moveToNext()) names.add(cursor.getString(0))
    }
    return names
}
```

Sorgu, uygulamanın görmesine izin verilen resimleri döndürür. İzin yoksa liste boş gelir ya da sorgu hata verir; uygulamanın izin vermediği bir dosyayı yolu ile açma yolu yoktur. Bu parça da platform kodudur ve çıktı iddia etmiyoruz. Model, platformun bu kuralını kurar; model platformun kendisi değildir.

Modelde izin kuralı bir basamak değildir. Medya deposundaki dosya, zincire eklenmemiş bir `Tier` olarak durabilir ve zincirde olmayan basamak okumayı yanıtlamaz.

## Sınırlayıcı Ölçüm

İki şeyi ölçeceğiz. İlki küçük resim: profil fotoğrafı küçültülüp belleğe alınmışsa okuma diske inmeden yanıtlanır. İkincisi galeri resmi: dosya medya deposunda var, ama okuma zincirinde yok.

Küçük resmi bellekte tutan işlev, bir dosyanın diskteki yolundan bellek değeri üretir.

```kotlin
// Thumbnails.kt — diskten okunan dosyanin kucuk resmini bellege alir
fun decodeThumbnails(source: Tier, keys: List<String>): Map<String, String> =
    keys.mapNotNull { key -> source.lookup(key)?.let { key to "kucuk:$it" } }.toMap()
```

```kotlin
// Main.kt — kucuk resim bellekte, galeri resmi zincirin disinda
fun main() {
    val privateDir = Tier("disk", indexDirectory("ozel", listOf("profil.jpg", "fatura.pdf")))
    val mediaStore = Tier("disk", indexDirectory("medya", listOf("galeri.png")))
    val memory = Tier("bellek", decodeThumbnails(privateDir, listOf("dosya.profil")))
    val chain = listOf(memory, privateDir)
    println("medya deposunda: ${mediaStore.lookup("dosya.galeri")}")
    val reads = readFileScreen(chain)
    reads.forEach { it.show() }
    countOrigins(reads)
}
```

```text
medya deposunda: medya/galeri.png
profil: anahtar=dosya.profil | deger=kucuk:ozel/profil.jpg -> bellek
fatura: anahtar=dosya.fatura | deger=ozel/fatura.pdf -> disk
galeri: anahtar=dosya.galeri | deger=yok -> varsayilan
bellek: 1
disk: 1
ag: 0
varsayilan: 1
```

Profil resmi belleğe alındığı için artık bellek kökenli ve değeri küçük resmin adını taşıyor. Fatura hâlâ diskten geliyor. Galeri resmi medya deposunda bulunuyor, yani dosya gerçekten var; ama okuma zincirinde olmadığı için yanıt varsayılan. Kural dosyanın var olup olmadığına değil, zincirin içeriğine bakar.

Galeri resmi uygulamanın kendi dizinine kopyalanırsa durum değişir. Dosya artık uygulamaya aittir ve zincirdeki disk basamağında durur.

```kotlin
// Main.kt — galeri resmi uygulamanin dizinine kopyalaninca zincire girer
fun main() {
    val files = listOf("profil.jpg", "fatura.pdf", "galeri.png")
    val privateDir = Tier("disk", indexDirectory("ozel", files))
    val reads = readFileScreen(listOf(privateDir))
    reads.forEach { it.show() }
    countOrigins(reads)
}
```

```text
profil: anahtar=dosya.profil | deger=ozel/profil.jpg -> disk
fatura: anahtar=dosya.fatura | deger=ozel/fatura.pdf -> disk
galeri: anahtar=dosya.galeri | deger=ozel/galeri.png -> disk
bellek: 0
disk: 3
ag: 0
varsayilan: 0
```

Üç okumanın üçü diskten geldi. Aynı dosya medya deposunda yanıtsızdı, uygulamanın dizininde yanıt veriyor; fark dosyanın içeriğinde değil, zincirdeki yerindedir.

Platformdaki karşılığı şudur: uygulama başka uygulamanın dosyasını yolunu bilse de doğrudan okuyamaz. Dosyaya erişimi izin kuralı belirler ve izin verilmemişse okuma, dosya diskte dursa da yanıtsız kalır. Modelde bu, dosyanın zincire hiç eklenmemesiyle gösterilir. Bu ölçümün söylemediği şey, iznin neden verilmediği ya da kullanıcının izni neden reddettiğidir.

**VK2.** Model, izni bir kural olarak değil, zincirin üyeliği olarak kurar. Platformda izin isteği, kullanıcının sonradan izni geri alması ve kullanıcının seçtiği tek dosya için geçici erişim verilmesi modelde yoktur.

## Özet

- Bu dersin kökeni: disk. Uygulamanın kendi dizinindeki bir dosyanın okuması disk basamağından yanıtlanır.
- Uygulamaya özel dizin izin istemez ve yalnız uygulamaya aittir; ortak medyaya medya deposu sorgusu ve izinle ulaşılır.
- Dizinde iki dosya varken ve galeri resmi uygulamaya kopyalanmadığında okumalar disk 2, varsayılan 1 çıktı.
- Küçük resim belleğe alınınca profil okuması bellek olur: bellek 1, disk 1, varsayılan 1.
- Zincirde olmayan dosya, medya deposunda var olsa da varsayılana düşer; kural dosyanın varlığını değil, zincirin içeriğini görür.
- Galeri resmi uygulamanın dizinine kopyalanınca aynı okuma disk olur: disk 3.

## Sonraki Adım

Bu derste dosya aynı aygıtın diskindeydi. Verinin çoğu başka bir makinededir ve ona bir istekle ulaşılır. Sıradaki ders, `Ağ İstemcisi`, bir isteğin yanıtının çözülüp ağ basamağını nasıl kurduğunu ve çözülemeyen bir alanın neye düştüğünü ölçer.
