HOME > android > basic

Android의 앱 데이터 폴더 경로 및 내부/외부 저장소 설명

JSFollow10 Mar 2018

Device에 App이 설치되면 App마다 사용할 수 있는 저장공간이 있습니다. 각 앱이 사용할 수 있는 directory마다 차이점이 있고, 자주 헷갈리는 부분이라서 한번 정리해보았습니다.

이 글은 안드로이드 Q가 공개되기 전에 쓰여졌습니다. 안드로이드 Q에서 외부 저장소의 새로운 정책인 Scoped Storage가 소개되었습니다. 그렇기 때문에 이 글의 내용은 안드로이드 P 이하의 디바이스에만 해당됩니다. Scoped storage에 대한 자세한 내용은 안드로이드 Q의 새로운 저장소 정책, Scoped Storage 알아보기를 참고해주세요.

Code(Apk) 위치

어떤 App이 설치되면 device 내부의 특정 dir에 apk, libs, oat 파일 등이 저장됩니다. Oreo부터 폴더명은 package의 이름에 random hashcode의 조합으로 생성됩니다.

  • /data/app/[package name]-[hashcode]/ 으로 폴더 생성됨
$ /data/app/com.codechacha.storages-v0U9I2KC_tE0MS5CN8NoTw== # ls
base.apk  oat  lib

Internal storage (내부 저장소)

내부 저장소도 특정 dir에 file, cache 등의 공간이 생성됩니다. cache의 경우 Device 내부에 저장공간이 부족한 경우 동의를 구하지 않고 삭제할 수 있는 폴더입니다. 삭제되서는 안되는 파일이라면 cache 폴더에 저장하면 안됩니다.

어떤 App의 Internal storage는 그 앱 스스로만 사용이 가능하며 다른 앱은 접근할 수 없습니다. 또한, file을 write/read 하는데 어떤 Permission도 필요하지 않습니다.

  • /data/user/[User number]/[package name]/ 으로 폴더 생성됨

adb shell로 확인해보면 여러 폴더들이 있습니다.

$ /data/user/0/com.codechacha.storages # ls
cache  code_cache  files  

App이 이런 path들은 쉽게 알 수 있도록 Context 객체에서 여러 method를 제공해줍니다.

// Internal storage
Log.d(TAG, "Internal private data dir: "
        + getDataDir().getAbsolutePath());
Log.d(TAG, "Internal private file dir: "
        + getFilesDir().getAbsolutePath());
Log.d(TAG, "Internal private cache dir: "
        + getCacheDir().getAbsolutePath());
03-10 22:25:18.979  6931  6931 D MainActivity: Internal private data dir: /data/user/0/com.codechacha.storages
03-10 22:25:18.979  6931  6931 D MainActivity: Internal private file dir: /data/user/0/com.codechacha.storages/files
03-10 22:25:18.979  6931  6931 D MainActivity: Internal private cache dir: /data/user/0/com.codechacha.storages/cache

External storage (외부 저장소)

외부 저장소도 내부 저장소와 비슷합니다. 하지만 외부저장소는 write/read 시 permission이 필요합니다. 그리고 모든 앱에서 접근이 가능하기 때문에 private을 보장하지 않습니다. 또한, PC에서 이 Storage에 접근이 가능하기 때문에 일시적으로 write/read가 불가능할 수 있습니다.

App 전용 폴더

App 전용으로 생성되는 storage가 있습니다. External이기 때문에 다른 앱에서도 접근이 가능하지만, 중요한 것은 이 App이 삭제된다면 이 공간도 함께 삭제된다는 점입니다. 따라서, 다른 App에서 공유되길 원하는 data는 이 곳에 저장되어서는 안됩니다.

  • /storage/emulated/0/Android/data/[package name]/ 으로 폴더 생성됨

Java로 path구하는 코드와 실행 Log입니다.

// External app's storage
Log.d(TAG, "External app's cache dir: "
        + getExternalCacheDir().getAbsolutePath());
Log.d(TAG, "External app's file dir: "
        + getExternalFilesDir(Environment.DIRECTORY_PICTURES));
03-10 22:52:49.350  7302  7302 D MainActivity: External app's cache dir: /storage/emulated/0/Android/data/com.codechacha.storages/cache
03-10 22:52:49.350  7302  7302 D MainActivity: External app's file dir: /storage/emulated/0/Android/data/com.codechacha.storages/files/Pictures

공용 폴더

공용 폴더는 앱들이 삭제된다고 해도 저장된 data가 삭제되지 않습니다.

  • /storage/emulated/0/[Content 종류]

Java로 path구하는 코드와 실행 Log입니다. getExternalStoragePublicDirectory()는 argument로 Environment.DIRECTORY_PICTURES처럼 Content 종류를 넘겨줍니다.

// External public storage
Log.d(TAG, "External public root dir: "
        + Environment.getExternalStorageDirectory());

Log.d(TAG, "External public file dir: "
        + Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES));
03-10 22:52:49.351  7302  7302 D MainActivity: External public root dir: /storage/emulated/0
03-10 22:52:49.352  7302  7302 D MainActivity: External public file dir: /storage/emulated/0/Pictures

Permissions

read/write를 하려면 AndroidManifest.xml에 다음 권한을 선언해야 합니다. Runtime permission이기 때문에 사용자의 허락을 받아야 합니다.

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

External storage 사용 가능 확인

PC에서 mount하는 경우 write/read가 안될 수 있기 때문에 사용하기 전에 사용가능한지 확인이 필요합니다.

/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {
        return true;
    }
    return false;
}

/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state) ||
            Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        return true;
    }
    return false;
}

정리

지금까지 안드로이드의 내부/외부 저장소에 대해서 알아보았습니다.

이 글은 안드로이드 Q가 공개되기 전에 쓰여졌습니다. 안드로이드 Q에서 외부 저장소의 새로운 정책인 Scoped Storage가 소개되었습니다. 그렇기 때문에 이 글의 내용은 안드로이드 P 이하의 디바이스에만 해당됩니다.

Scoped storage에 대한 자세한 내용은 안드로이드 Q의 새로운 저장소 정책, Scoped Storage 알아보기를 참고해주세요.

참고