Android Storage 요약
Published by Woong Geun Jang,
레퍼런스
- 안드로이드 개발자 레퍼런스 (링크)
개요
안드로이드에서는 데이터를 저장하는 여러 옵션을 제공하는데,
각각의 솔루션은 다음의 고려사항에 따라 결정된다.
- 데이터 크기
- 데이터 종류
- 데이터의 접근권한
여러 옵션은 다음과 같다.
- Internal file storage디바이스 파일 시스템에 앱전용 데이터를 저장
- External file storage공유 파일 시스템에 파일을 저장
- Shared Preference
- Databases
위의 옵션들은 External file storage에 저장되는 특정 파일형태를 제외하고는
모두 app-private data를 위한 옵션들이라고 한다.
파일을 다른 앱과 공유하기 위해서는 두 가지 옵션이 있는 것으로 보인다.
- FileProvider API
- Content Provider
Internal file storage
Internal file storage는 Internal storage와 Internal cache files 기능을 제공한다.
- Internal storage위에서 언급했던 것처럼, app-private-data를 저장하기 위함이고,특징으로는 app을 지우면 같이 사라진다.
- Internal cache files임시로 데이터를 보관하고 싶을 때 사용하는 저장소.특징은 Android가 Internal Storage Space 공간이 적을 때, 임의로 캐시파일들을 지울 수 있다.그렇지만, 시스템이 지울 거라고 예상하고 캐쉬파일을 막 쓰면 안되고,항상 캐쉬파일 공간의 크기를 정해놓고 사용해야 한다. 대략 1MB가 적당.마찬가지로 앱을 지우면 같이 사라진다.
External file storage
external file storage는 앱을 지울 때 데이터가 같이 지워지는 것을 방지하기 위한 파일시스템.
특징은 유저가 USB로 연결해서 데이터를 읽을 수 있지만, 그렇다고 다른 앱에서 이 데이터에 접근할 수 있는 것은 아니라는 것.
Shared Preferences
많은 데이터를 저장할 필요없을 때 사용할 수 있는 Key-Value 형태의 데이터 스트럭쳐
Databases
안드로이드는 SQLite 데이터베이스를 지원한다. 이 데이터베이스는 그 데이터베이스를 생성한 해당 앱만 사용이 접근이 가능하다.
보통 SQLite를 직접 접근해서 사용하지 않고 안드로이드에서 제공하는 헬퍼 라이브러리인 Room을 이용한다고 한다.
Room 라이브러리는 Object Mapping 기능도 제공한다고 한다.
파일을 디바이스 저장공간에 저장
Internal과 External이라는 단어는 개발자들에게 엄청난 혼동을 주는데, 이 이름의 유래는 안드로이드 초창기에서 시작된다. 그 때는 대부분의 디바이스가 빌트인 비휘발성 메모리(internal storage)와 제거가 가능한 micro SD카드(external storage)로 구분되었다. 그런데 현재 대부분의 디바이스들은 영구저장공간을 internal과 external로 파티션을 나눠서 사용하기 때문에 의미가 많이 달라졌다.
그래도 아직까지 기능상으로 다른 점이 몇 가지 존재하는데 이는 다음과 같다.
Internal Storage | External storage |
항상 이용가능 | 항상 이용가능하지 않음. 유저가 external storage를 USB로 마운트하거나 특정경우 제거할 수 있음 |
여기 저장된 파일들은 앱만 접근 가능 | 여기 저장된 파일은 누구나 읽기 가능
(다른 앱과 데이터를 공유하는 기능과는 다름) |
앱을 지우면 데이터도 지워짐 | getExternalFilesDir을 통해 받은 경로에 저장하면 앱을 지워도 날아가지 않음 |
Tips
앱도 External Storage에 저장할 수 있다고 한다.
보통 Internal Storage가 용량이 작기 때문에 사이즈가 큰 앱의 경우 External Storage에 저장할 때 사용된다고 한다.
내부저장공간에 파일쓰기
getFilesDir()을 통해 내부저장공간 경로를 얻을 수 있다.
이 경로에 FileOutputStream을 열고 쓰면 된다.
내부저장캐쉬에 파일쓰기
캐쉬에 저장하기 위해서는 File.createTempFile을 통해 파일을 생성하고 마찬가지로 FileOutputStream으로 쓰면 된다.
내부저장공간에 저장된 파일 읽기
openFileInput(name)을 통해서 읽을 수 있다.
내부저장공간에 저장된 모든 파일이름은 fileList()를 통해 얻을 수 있다.
외부
내부저장공간에 저장된 파일 지우기
context.deleteFile(filename)
외부저장공간에 파일쓰기
1)storage permission 요청을 하고 해당 2)storage가 가용한 지 확인한 후에 두 가지 타입의 파일을 저장할 수 있다.
- public files다른 앱이나 유저가 제한없이 사용이 가능한 파일들. 유저가 앱을 지워도 남아있다.
- private files앱에 속하는 파일들로 앱을 지우면 지워진다.비록 기술적으로 다른 앱에서 접근은 가능하지만, 의도상 외부 유저에게 기능을 제공하지 않는다.
외부공간 permission 요청하기
외부공간에 데이터를 저장하려면 WRITE_EXTERNAL_STORAGE permission을 manifest 파일에 명시해야 한다.
(Write 권한이 승인되면, 암묵적으로 Read도 승인되기 때문에 READ 권한은 따로 요청할 필요가 없다)
안드로이드 4.4 이후부터는 private external storage directory에 읽기/쓰기는 따로 권한요청이 필요없다.
외부공간 가용여부 확인하기
getExternalStorageState()를 통해 MEDIA_MOUNTED를 반환받으면 읽기/쓰기가 가능한 상태다.
외부공간 public 디렉토리에 파일쓰기
getExternalStoragePublicDirectory()를 통해서 얻은 File객체에 파일을 쓰면 된다.
*만약 MediaScanner로부터 파일을 숨기려면, 빈파일에다가 .nomedia 확장명을 붙여서 external file directory에 저장하면 된다.
외부공간 private 디렉토리에 파일쓰기
getExternalFilesDir를 통해서 File객체를 받아오면 된다.
*외부공간은 내부메모리를 외부공간으로 파티션해서 사용하는 경우와 SD카드를 사용하는 경우가 있는데,
안드로이드 4.4(API 19) 이후부터는 getExternalFilesDirs를 통해 이 두 저장공간 위치를 얻을 수 있다.
외부공간에 데이터를 저장할 때는 디렉토리명을 시스템에서 제공해 주는 상수로 정의하면,
시스템에서 적절하게 처리할 수 있다. 예로 들어, Environment.DIRECTORY_PICTURES로 데이터를 저장하면 MediaScanner에서 디렉토리를 기준으로 사진들을 찾아낼 수 있다.
참고로 MediaScanner가 인식하는 디렉토리에 파일을 썼다고 해서 바로 인식되는 것은 아니여서, 사진을 저장한 후에 BroadCast로 MediaScanner가 그 파일을 스캔하도록 강제해야 한다.
외부공간에 저장된 파일 지우기
myFile.delete();
여유공간 확인하기
파일의 사이즈를 저장하기 전에 알 수 있으면, getFreeSpace 또는 getTotalSpace를 통해 공간이 충분한 지 확인할 수 있고, IOException을 막을 수 있다.