개발/android 개발
[안드로이드 잡학] File 저장하기 (internal , external storage)
알고싶은 승민
2022. 3. 14. 19:00
파일 저장소 구분
internal: 항상 접근 가능, 파일을 저장한 앱에서만 접근 가능, 앱 제거시 함께 사라짐
external: removable한 저장소 (usb, disk 등은 항상 제거될 수 있다), 어디서든 접근 가능, 앱 제거해도 그대로 남아있음.
주의 사항) app-specific external은 그냥 외부 disk (sdcard) 등에 저장될 뿐 앱과 함께 제거되고 접근 가능한 속성을 그대로 가진다.
Internal 저장소 사용 예시
class InternalFileStorageUseCase {
private lateinit var context: Context
// 내부 저장소에 저장된 파일에 접근하기
fun accessStoredFile(): File {
val dir = context.filesDir
val filename = "sample.txt"
val file = File(dir, filename)
return file
}
// Stream 사용해서 파일 저장하기
fun storeFileUsingStream() {
val filename = "sample.txt"
val fileContent = "Hello World!"
// API 24 이상에서, MODE_PRIVATE 사용 안하면, SecurityException 발생
context.openFileOutput(filename, Context.MODE_PRIVATE).use {
it.write(fileContent.toByteArray())
}
}
// Stream 사용해서 파일 접근하기
fun accessFileUsingStream() {
val filename = "sample.txt"
context.openFileInput(filename).bufferedReader().useLines { lines ->
lines.fold("") { some, text ->
"$some\n$text"
}
}
}
// 파일 리스트 받아오기
fun viewListOfFiles() {
var files: Array<String> = context.fileList()
}
// 폴더 만들기
fun createNestedDir() {
val dirName = "sub"
context.getDir(dirName, Context.MODE_PRIVATE)
}
// 캐시 파일 만들기
fun createCacheFile() {
val cacheDir = context.cacheDir
val filename = "temp.jpg"
File.createTempFile(filename, null, cacheDir)
}
// 캐시 파일 접근하기, 단 캐시 파일의 경우 안드로이드가 임의로 지워버릴 수 있음.
fun accessCacheFile(): File {
val filename = "temp.jpg"
val cacheFile = File(context.cacheDir, filename)
return cacheFile
}
// 캐시 파일 제거하기
// 안드로이드가 캐시 파일을 제거를 보장하지는 않음. 적절한 처리할 것
fun removeCacheFile() {
val cacheFile = accessCacheFile()
// case 1
cacheFile.delete()
// case 2
context.deleteFile(cacheFile.name)
}
}
External 저장소 사용 예시
// 앱 특화된 external 저장소로, API 19 이상부턴 별다른 권한 없이 접근이 가능하다.
// 앱을 제거할 때 함께 제거된다.
// 항상 접근이 보장되는게 아니기 때문에, 앱의 메인 기능을 이 파일에 의존하면 안된다.
// API 28 이하에서는 적절한 권한만 있으면, 다른 앱의 external 영역에 접근할 수 있다.
// API 29 이상에서는 scoped storage로 관리하면 된다, scoped access를 허용하면, 다른 앱의 external 파일에 접근 못함.
class ExternalFileStorageUseCase {
private lateinit var context: Context
// external은 항상 접근가능하지 않다. (sd card, usb를 생각해봐라 사용자가 마음대로 뽑아버릴 수 있다.)
// 쓰기 가능한 상태인지 체크
fun isExternalStorageWritable(): Boolean {
return Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED
}
// 읽기 가능한 상태인지 체크
fun isExternalStorageReadable(): Boolean {
return Environment.getExternalStorageState() in
setOf(Environment.MEDIA_MOUNTED, Environment.MEDIA_MOUNTED_READ_ONLY)
}
// 여러 볼륨 중에 고르기
// API 18 이하에서는 하나만 있다.
fun selectPhysicalStorageLocation(): File {
val externalStorageVolumes: Array<out File> =
ContextCompat.getExternalFilesDirs(context, null)
val primaryExternalStorage = externalStorageVolumes[0]
return primaryExternalStorage
}
// app-specific 외부 저장소에 파일 접근하기
fun accessFile(): File {
val externalDir = context.getExternalFilesDir(null)
val filename = "sample.txt"
val file = File(externalDir, filename)
return file
}
// API 30 이상부터 앱에서 external storage에 본인 소유 directory 못만든다.
fun createCacheFile(): File? {
if (isExternalStorageWritable()) {
val externalCacheDir = context.externalCacheDir
val filename = "temp.jpg"
val file = File(externalCacheDir, filename)
return file
} else {
return null
}
}
}
참고 자료
Data and File Storage Overview : 저장할 데이터의 속성에 따라서 무슨 API를 봐야할 지 table 형태로 정리된 자료, 데이터 저장소 작업이 필요할 때 항상 처음으로 참고할 웹사이트
Raywenderlich Saving Data On Android : 안드로이드 데이터 저장 관련 시리즈 중 File 관련 내용만 발췌, 전체 내용을 보고 한번 자신만의 UseCase를 정리하면 요긴하게 사용할 수 있을 것 같음.
Access app-sepcific files : 앱에서만 접근할 수 있는 (context에서 제공하는) 파일 저장소 API, 사용법을 보고 정리하면 좋을 듯