| 구분 | raw 폴더 | 앱 전용 외부 메모리 | 공유 외부 메모리 |
|---|---|---|---|
| 위치 | /res/raw | /Android/data/패키지명/files | /sdcard |
| 클래스 | InputStream | FileInputStream | FileInputStream |
| 접근 메소드 | openRawResource() | getExternalFilesDir(null) | System.getenv("EXTERNAL_STORAGE") |
| 권한 필요 | ❌ | ❌ (앱 전용) | ✅ (READ/WRITE/MANAGE) |
| 쓰기 가능 | ❌ (읽기 전용) | ✅ | ✅ |
| 공유 여부 | 앱 내부 | 앱 전용 | 여러 앱 공유 |
1. 읽기 전용 파일 (raw 폴더 활용)
-
개발 PC에서 미리 작성한 텍스트 파일(사용 약관 등)을 앱에 포함시킬 때 사용한다.
-
파일은
/res/raw폴더에 저장한다. -
한글 손상 방지를 위해 인코딩을 UTF-8로 설정한다.
-
접근:
resources.openRawResource(R.raw.파일명) -
반환: InputStream (
FileInputStream이 아님) -
읽어올 데이터의 크기:
inputStream.available()
val inputStream = resources.openRawResource(R.raw.raw_test)
val txt = ByteArray(inputStream.available())
inputStream.read(txt)
binding.tvRaw.text = txt.toString(Charsets.UTF_8)
inputStream.close()2. 외부 메모리
- 음악·영상·사진처럼 여러 앱이 공유해 사용하는 파일을 저장하는 공간으로, 내장 메모리보다 큰 저장 공간을 쓸 수 있다.
2.1. 권한 설정
AndroidManifest.xml에READ/WRITE/MANAGE_EXTERNAL_STORAGE퍼미션을 추가하고,<application>에requestLegacyExternalStorage="true"속성을 넣는다.
<uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<application
android:requestLegacyExternalStorage="true">MainActivity.kt코드에서는 SDK 버전(Android R 이상/미만)에 따라 분기하여 권한을 요청한다.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (!Environment.isExternalStorageManager()) {
val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
this.startActivity(intent)
}
} else {
val permissions = arrayOf(
android.Manifest.permission.READ_EXTERNAL_STORAGE,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
)
ActivityCompat.requestPermissions(this, permissions, 1001)
}2.2. 경로 확인 방법
앱 전용 외부 메모리와 공유 외부 메모리로 구분된다.
-
앱 전용 경로:
getExternalFilesDir(null)- → 예:
/storage/emulated/0/Android/data/패키지명/files
- → 예:
-
공유 경로:
System.getenv("EXTERNAL_STORAGE")
val externalDir = System.getenv("EXTERNAL_STORAGE")
// 결과: /sdcard2.3. 파일 읽기
경로만 지정하는 점을 빼면 raw 파일 처리와 거의 동일하며,
FileInputStream(경로)을 사용한다.
val fileInputStream = FileInputStream(externalDir + "/exmem.txt")2.4. 디렉터리 생성/삭제
File객체의mkdir()(생성),delete()(삭제) 사용mkdirs()는mkdir -p처럼 중간 경로까지 한 번에 생성
val externalDir = System.getenv("EXTERNAL_STORAGE") + "/test_dir"
val pathDir = File("$externalDir/test")
binding.btnMkdir.setOnClickListener {
pathDir.mkdir() // mkdirs()는 mkdir -p 와 동일 (중간 경로까지 생성)
}
binding.btnRmdir.setOnClickListener {
pathDir.delete()
}2.5. 폴더/파일 목록 확인
File(경로).listFiles()가 파일 목록을 배열로 반환한다.
var sysFiles = File(sysDir).listFiles()isDirectory/isFile로 폴더와 파일을 구분한다.
for (i in sysFiles.indices) {
if (sysFiles[i].isDirectory == true)
strFileName = "<폴더> " + sysFiles[i].toString()
else
strFileName = "<파일> " + sysFiles[i].toString()
}- 시스템 폴더 루트는
Environment.getRootDirectory()(=/system)로 얻는다.
val sysDir = Environment.getRootDirectory().absolutePath // /system3. 실습: 간단 이미지 뷰어
외부 저장소(
/sdcard/test_dir)의 이미지를 버튼으로 넘겨 보는 앱이다.
- 핵심 로직:
listFiles()로 폴더 내 파일을 가져온 뒤,isFile이면서 파일명이"renoir"로 시작하는 것만 리스트에 추가 - 이미지 표시는
BitmapFactory.decodeFile(경로)로 비트맵을 만들어ImageView에 설정 - “이전/다음 그림” 버튼은 인덱스(
curNum)를 ±1 하고abs(curNum % 10)로 순환시켜 처리