한편으로 외부 저장소는 데이터와 파일을 전화기의 외부 SD카드 Secure Digital Card로 저장한다. 내부/외부 저장소에 대한
개념은 비슷하다. 따라서 앞서 살펴본 내용, 즉 SharedPreferences 대비 외부 저장소의 장단점을 살펴보자.
SharedPreference는 오버헤드가 크지 않기 때문에 단순한 Map 객체 읽기/쓰기 작업은 디스크 읽기/쓰기 작업에 비해 훨씬
더 효과적이다. 하지만 SharePreference는 간단한 기본형 값으로 제한되며, 본질적으로 유연함을 효율성을 바꾸고 있는 셈이다.
내부/외부 저장소 매커니즘을 통해 훨씬 더 많은 데이터 청크(즉, 완전한 XML 파일)는 물론이고, 더욱 복잡한 형태의 데이터
(미디어 파일과 이미지 파일 등)를 저장할 수 있다.
내부 저장소 대비 외부 저장소는 어떤 차이가 있을까? 이 둘 사이의 장단점은 좀 더 미묘하다. 우선 저장소 공간의 크기(메모리)를
생각해보자. 사용자가 소유한 전화기에 따라 저장 공간은 다양하지만 내부 메모리 전체 크기가 아주 작을 수 있다.
외부 저장소는 어떤 SD카드를 쓰는지에 따라 크기가 달라진다.
내부 저장소의 경우 데이터는 자신의 애플리케이션에 의해서만 접근이 가능하며, 따라서 잠재적으로 악의적인 외부 애플리케이션으로부터
매우 안전한다. 장점은 애플리케이션이 삭제되면 내부 메모리 또한 정리된다는 점이다.
외부 저장소의 경우 본질적으로 읽기와 쓰기가 가능하기 때문에 저장된 모든 파일은 외부 애플리케이션과 사용자에게 노출된다.
따라서 파일이 안전하고 깨끗하게 유지될지 보장할 수 없다.
다음 예제를 통해 외부 SD 카드에 실제로 어떻게 접근할 수 있는지 살펴보자.
package jwei.apps.dataforandroid.ch1;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import jwei.apps.dataforandroid.R;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
public class ExternalStorageExample extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
String fileName = "my_file.txt";
String msg = "Hello World.";
boolean externalAvailable = false;
boolean externalWriteable = false;
String state = Environment.getExternalStorageState();
if (state.equals(Environment.MEDIA_MOUNTED)) {
// 미디어는 사용 가능하며, 쓰기도 가능하다
externalAvailable = true;
externalWriteable = true;
} else if (state.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
// SD 카드는 사용 가능하지만, 쓰기는 불가능하다
externalAvailable = true;
} else {
// 여러 상황에 실패할 수 있다.
// 특별한 동작은 없다.
}
if (externalAvailable && externalWriteable) {
// API 레벨 7 혹은 그 이하 버전에서 SD 카드 디렉토리를 가져온다.
File root = Environment.getExternalStorageDirectory();
File f = new File(root, fileName);
try {
// 내부 저장소 쓰기 방법과 차이가 있을에 유의한다.
FileWriter fWriter = new FileWriter(f);
BufferedWriter out = new BufferedWriter(fWriter);
out.write(msg);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
} else {
Log.e("LOG_TAG", "SD CARD UNAVAILABLE");
}
}
}
위 코드를 실행하기 위해 매니페스트 파일에 WRITE_EXTERNAL_STORAGE 권한을 추가하는 것을 잊지 말자.
여기서 실제로 마운트되고 쓰기 가능한 외부 SD 카드를 탐지할 수 있게 Environment 클래스의 getExternalStorageState() 메소드를 호출했다.
이런 사전 확인 없이 파일을 읽거나 쓴다면 에러가 발생할 수 있다.
SD 카드가 마운트돼 실제로 쓰기가 가능한 상황이라면 API 레벨 7 혹은 그 이후에 getExternalStorageDirectory() 를 호출해 SD 카드의 루트
파일 경로를 가져올 수 있다. 이 관점에서 단순히 새로운 파일을 생성해 FileWriter와 BufferedWritter를 초기화하고 문자열을 팡리에 쓰고자 한다.
여기서 주목해야 할 부분은 외부 저장소를 처리할 때 디스크에 쓰는 방법이 이전에 살펴본 내부 저장소에 쓰는 방법과 다르다는 점이다.
이는 실제로 기억하고 이해해야 할 중요한 부분이며, 이러한 쓰기 메소드에 대해 특별히 강조했던 이유이기도 하다. 내부 저장소 예제에서는
Context 클래스의 openFileOutput() 메소드(두 번째 인자로 모드를 받는)를 호출해 FileOutputStream 개체를 얻었다.
MODE_PRIVATE를 전달하면 이면에서 FileOutStream으로 파일을 생성하고 쓸 때마다 해당 파일은 애플리케이션의 고유 ID로 암호화되고
서명된다. 따라서 외부 애플리케이션은 해당 파일의 내용에 접근할 수 없다.
하지만 외부 저장소에 파일을 생성하고 쓸 때는 기본적으로 어떠한 보안 적용 없이 파일이 생성되기 때문에 모든 애플리케이션은 이 파일을
읽거나 쓸 수 있따. 이는 내부 저장소가 아니라 외부 SD 카드에 쓸 때에는 표준 자바 메소드를 사용할 수 있는 이유이기도 하다.
마지막으로 유념해야 할 것은 이클립스의 DDMS perspective에서 새로 생성된 파일을 볼 수 있기 때문에 SD 카드가 설정돼 있따면
DDMS에서 새롭게 생성된 텍스트 파일을 쉽게 확인할 수 있으며 애플리케이션을 개발할 때 DDMS perspective를 잘 활요하면 빠르게 파일을
넣거나 뺄 수 있으며, 디스크에 쓰고 있는 파일을 모니터링할 수 있다.
API 레벨 8 이후에 소개된 외부 저장소 쓰기 관련 변경 사항에 대해 짧게 이야기하고자 한다. 실제로 이 변경에 대한 내용은
문서를 참고하기 바란다.
하지만 API 레벨 8이나 이상 버전의 고수준 관점에서는 단순히 다음 두 가지 새로운 기본 메소드만 의미가 있다.
getExternalFilesDir(String type)
getExternalStoragePublicDirectory(String type)
이러한 메소드 각각에 대해 이제 type 매개변수를 전달할 수 있음을 확인할 수 있을 것이다. type 매개변수는 파일의 종류를 지정할 수 있게 하며,
올바른 하위 폴더로 구성되게 만단다. 첫 번째 메소드에서 반환된 외부 파일 디렉토리 루트는 애플리케이션마다 다르기 때문에 애플리케이션이
삭제될 때 관련된 모든 파일 역시 외부 SD로부터 제거된다. 두 번째 메소드에서 반환된 파일 디렉토리 루트는 공개돼 있는 것으로, 이 경로에
저장된 파일은 애플리케이션이 삭제되더라도 계속 남아있게 된다. 저장하고자 하는 파일의 종류에 따라 어떠한 것을 사용할지 결정하면 된다.
예를 들어 파일이 애플리케이션 내에서 재생된 미디어 파일이고, 사용자가 애플리케이션을 삭제하려고 한다면 사용자에게 이 파일은 더 이상
필요가 없을 것이다.
하지만 애플리케이션을 통해 사용자가 자신의 전화기에 배경 화면을 다운로드할 수 있게 허용한다면 이 경우에는 공개된 디렉토리로 이미지
파일을 저장하게 고려해야 한다. 그 결과로 사용자가 애플리케이션을 삭제한다고 해도 이 파일은 여전히 시스템에 의해 접근 될 수 있을 것이다.
지정할 수 있는 type 매개변수는 다음과 같다.
DIRECTORY_ALARMS
DIRECTORY_DCIM
DIRECTORY_DOWMLOADS
DIRECTORY_MOVIES
DIRECTORY_MUSIC
DIRECTORY_NOTIFICATIONS
DIRECTORY_PICTURES
DIRECTORY_PODCASTS
DIRECTORY_RINGTONES
지금까지 내부/외부 저장소 매커니즘에 대한 다소 장황한 글을 마쳤다.
'Programing > Android' 카테고리의 다른 글
[SQL/DB] SQLite 데이터베이스 (0) | 2013.11.15 |
---|---|
[SQL/DB] 내부 저장소 메소드 (0) | 2013.11.15 |
[SQL/DB] SharedPreferences의 일반적인 사용 사례 (0) | 2013.11.15 |
[SQL/DB] SharedPreferences의 사용 (0) | 2013.11.13 |