[6] 데이터 저장 [2] 파일 저장

Saving Files

THIS LESSON TEACHES YOU TO

  1. Choose Internal or External Storage
  2. Obtain Permissions for External Storage
  3. Save a File on Internal Storage
  4. Save a File on External Storage
  5. Query Free Space
  6. Delete a File

YOU SHOULD ALSO READ


Android uses a file system that’s similar to disk-based file systems on other platforms. This lesson describes how to work with the Android file system to read and write files with the FileAPIs.

디스크 기반의 다른 플랫폼에서 쓰는 파일 시스템과 비슷한 파일 시스템을 사용합니다. 이번 시간에는 어떻게 안드로이드 파일 시스템을 다루는 지 알아봅니다. File API를 사용해서 읽고 써 보겠습니다.

A File object is suited to reading or writing large amounts of data in start-to-finish order without skipping around. For example, it’s good for image files or anything exchanged over a network.

파일 오브젝트는 큰 데이터를 쓰고 읽는데에 적합합니다. 예를 들어 이미지 파일이나 네트워크로 파일 교환 하는 데에 좋지요.

This lesson shows how to perform basic file-related tasks in your app. The lesson assumes that you are familiar with the basics of the Linux file system and the standard file input/output APIs in java.io.

이번 레슨에서는 어떻게 파일관련된 일을 앱에서 수행할 수 있는지 알아봅니다. 우리가 리눅스 파일 시스템이나 표준 입출력 API를 잘 안다는 가정 하에 진행합니다.

Choose Internal or External Storage


All Android devices have two file storage areas: “internal” and “external” storage. These names come from the early days of Android, when most devices offered built-in non-volatile memory (internal storage), plus a removable storage medium such as a micro SD card (external storage). Some devices divide the permanent storage space into “internal” and “external” partitions, so even without a removable storage medium, there are always two storage spaces and the API behavior is the same whether the external storage is removable or not. The following lists summarize the facts about each storage space.

크게 두 곳의 파일 저장 공간이 있습니다. “내부”, “외부”. 이 이름은 안드로이드의 초창기부터 쓰여 왔습니다. 비휘발성 내장 메모리를 사용하고, 외부의 탈착 가능한 micro sd 카드를 삽입할 수 있지요. 일부 디바이스는 영구적 공간이 있는데요, internal 과 external 파티션 사이에 있습니다. 그래서 심지어 외장메모리가 없이도, 언제나 두 개의 스토리지 공간이 있고, API는 external 스토리지가 있건 없건 비슷하게 행동하는 것이지요. 다음 리스트는 각각의 메모리 공간에 대한 요약입니다.

Internal storage:

  • It’s always available.
  • Files saved here are accessible by only your app by default.
  • When the user uninstalls your app, the system removes all your app’s files from internal storage.
  • 언제나 사용가능
  • 앱에서 저장하는 파일의 기본 저장소
  • 앱 삭제 시, 관련된 파일도 삭제됨

Internal storage is best when you want to be sure that neither the user nor other apps can access your files.

내부 스토리지는 사용자나 앱이 아니면 파일에 접근하지 못하게 하는 좋은 방법입니다.

External storage:

  • It’s not always available, because the user can mount the external storage as USB storage and in some cases remove it from the device.
  • It’s world-readable, so files saved here may be read outside of your control.
  • When the user uninstalls your app, the system removes your app’s files from here only if you save them in the directory from getExternalFilesDir().
  • 언제나 사용가능한 것은 아님. 사용자가 USB 저장소를 외부 저장소로써 사용할 수도 있기 때문. 제거했다면 사용 못하는 것
  • 어디서나 읽을 수 있음. 여기에 저장된 파일은 우리 의도 밖에서 읽힐 수 있음
  • 앱을 삭제하면 앱의 앱에 관련된 파일은 일부만 삭제됨. 그 파일은 getExternalFilesDir() 으로 쓰여진 파일들만.

External storage is the best place for files that don’t require access restrictions and for files that you want to share with other apps or allow the user to access with a computer.

외부 저장소는 접근 제한을 필요로 하지 않는 파일을 위해 좋습니다. 그리고 다른 앱이나 사용자가 컴퓨터를 사용해서 공유할 수 있게 하기 좋지요.

Tip: Although apps are installed onto the internal storage by default, you can specify the android:installLocationattribute in your manifest so your app may be installed on external storage. Users appreciate this option when the APK size is very large and they have an external storage space that’s larger than the internal storage. For more information, see App Install Location.

Tip: 앱이 내부 저장소에 기본적으로는 저장되더라도, 우리는 명시해 줄 수 있습니다. android:installLocation 속성응ㄹ 매니페스트 파일에, 그래수 우리의 앱은 외부 저장소에 저장될 수 있지요. 사용자는 이 옵션에 대해 좋아할 수 있습니다. APK 사이즈가 매우 크고 외부 저장소가 충분히 크다면요. App Install Location 을 참고해 보세요.

Obtain Permissions for External Storage


To write to the external storage, you must request the WRITE_EXTERNAL_STORAGE permission in your manifest file:

외부 저장소에 쓰려면, 반드시 WRITE_EXTERNAL_STORAGE 권한을 획득해야 합니다. 매니페스트 파일에서 할 수 있어요.

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

Caution: Currently, all apps have the ability to read the external storage without a special permission. However, this will change in a future release. If your app needs to read the external storage (but not write to it), then you will need to declare the READ_EXTERNAL_STORAGE permission. To ensure that your app continues to work as expected, you should declare this permission now, before the change takes effect.

주의 : 현재, 모든 앱은 외부 저장소에 특별한 권한 없이 쓸 수 있습니다. (근데 이제 바뀌었지 않았나요? 외부 저장소에 못 쓸건데???;;;)

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

However, if your app uses the WRITE_EXTERNAL_STORAGE permission, then it implicitly has permission to read the external storage as well.

하지만, 우리 앱이 WRITE_EXTERNAL_STORAGE 권한을 쓰면, 명시적으로 읽기 권한도 얻습니다.

You don’t need any permissions to save files on the internal storage. Your application always has permission to read and write files in its internal storage directory.

내부 저장소에 파일을 저장할 때 어떠한 권한도 필요 없습니다. 우리의 앱은 언제나 내부 저장소를 읽고 쓸 수 있습니다.

Save a File on Internal Storage


When saving a file to internal storage, you can acquire the appropriate directory as a File by calling one of two methods:

내부 저장소에 파일을 저장하려면 적당한 디렉토리를 파일로써 얻어야합니다. 한 두개의 메서드를 불러야 합니다.

getFilesDir()
Returns a File representing an internal directory for your app.
앱에서 사용할 내부 디렉토리를 대표하는 파일을 리턴합니다.
getCacheDir()
Returns a File representing an internal directory for your app’s temporary cache files. Be sure to delete each file once it is no longer needed and implement a reasonable size limit for the amount of memory you use at any given time, such as 1MB. If the system begins running low on storage, it may delete your cache files without warning.
앱에서 사용할 임시 캐시 파일을 저정하는 디렉토리를 대표하는 파일을 리턴합니다. 이 파일을 지워야 함을 숙지하시길 바랍니다. 더 이상 필요 없으면 지워주는 것이 좋습니다. 

To create a new file in one of these directories, you can use the File() constructor, passing the File provided by one of the above methods that specifies your internal storage directory. For example:

만들기 위해서, File() 생성자를 사용하면 됩니다. File 을 전내줍니다. 이 것은 위의 메서드에서 리턴된 파일이지요.

File file = new File(context.getFilesDir(), filename);

Alternatively, you can call openFileOutput() to get a FileOutputStream that writes to a file in your internal directory. For example, here’s how to write some text to a file:

또는, openFileOutput() 을 FileOutputStream 을 얻기 위해 호출 할 수 있습니다. 그 스트림은 file 을 우리의 내부 디렉토리에 씁니다. 예를 들어, 어떻게 텍스트를 파일에 쓰는지 보겠습니다.

String filename = "myfile";
String string = "Hello world!";
FileOutputStream outputStream;

try {
  outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
  outputStream.write(string.getBytes());
  outputStream.close();
} catch (Exception e) {
  e.printStackTrace();
}

Or, if you need to cache some files, you should instead use createTempFile(). For example, the following method extracts the file name from a URL and creates a file with that name in your app’s internal cache directory:

또는, 캐시 파일이 필요한 경우에는 createTempFile()을 사용합니다. 예를 들어 다음 메서드는 파일 이름을 URL 로부터 따와서 파일을 내부 캐시 디렉토리에 생성하는 것을 보여줍니다.

public File getTempFile(Context context, String url) {
    File file;
    try {
        String fileName = Uri.parse(url).getLastPathSegment();
        file = File.createTempFile(fileName, null, context.getCacheDir());
    catch (IOException e) {
        // Error while creating file
    }
    return file;
}

Note: Your app’s internal storage directory is specified by your app’s package name in a special location of the Android file system. Technically, another app can read your internal files if you set the file mode to be readable. However, the other app would also need to know your app package name and file names. Other apps cannot browse your internal directories and do not have read or write access unless you explicitly set the files to be readable or writable. So as long as you use MODE_PRIVATE for your files on the internal storage, they are never accessible to other apps.

주의 : 내부 저장소 디렉토리는 앱의 패키지 네임에 의해서 정해지는데요, 안드로이드 시스템의 특별한 위치에 있게 됩니다. 기술적으로 다른 앱은 이 파일을 읽을 수는 있는데요, 파일 모드가 readable 일 때 가능하죠. 그치만 다른 앱이 우리의 패키지 네임과 파일 네임을 알 필요가 있습니다. 다른 앱은 내부 디렉토리를 볼 수 없고 읽거나 쓰는 권한이 없습니다. 따로 readable 이나 writable 권한을 명시적으로 정해주기 전까지는 말이지요. 그래서 MODE_PRIVATE 를 쓰는 한 다른 앱을 접근하지는 못합니다.

Save a File on External Storage


Because the external storage may be unavailable—such as when the user has mounted the storage to a PC or has removed the SD card that provides the external storage—you should always verify that the volume is available before accessing it. You can query the external storage state by calling getExternalStorageState(). If the returned state is equal to MEDIA_MOUNTED, then you can read and write your files. For example, the following methods are useful to determine the storage availability:

외부 저장소가 사용가능하지 않을 수 있기 때문에 – SD카드를 뺐을 때처럼 – 접근하기 전에 사용 가능한 공간을 체크해야 합니다. getExternalStorageState()를 사용해서 외부 저장소 상태를 요청할 수 있습니다. 만약 state 가 MEDIA_MOUNDED 라면, 파일을 읽고 쓸 수 있습니다. 예를 들어 다음 메서드는 저장소의 사용가능성을 알아보는 데에 유용하지요.

/* 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;
}

Although the external storage is modifiable by the user and other apps, there are two categories of files you might save here:

비록 외부 저장소가 우리 앱이나 다른 앱에 의해서 수정되었어도, 2 개의 카데고리가 있습니다.

Public files
Files that should be freely available to other apps and to the user. When the user uninstalls your app, these files should remain available to the user.For example, photos captured by your app or other downloaded files.
앱이나 사용자가 자유롭게 사용가능한 파일입니다.  유저가 앱을 지울 때, 이 파일들은 사용 가능하게 남아있게 됩니다.  예를 들어 사진캡쳐파일 같은 경우지요.
Private files
Files that rightfully belong to your app and should be deleted when the user uninstalls your app. Although these files are technically accessible by the user and other apps because they are on the external storage, they are files that realistically don’t provide value to the user outside your app. When the user uninstalls your app, the system deletes all files in your app’s external private directory.For example, additional resources downloaded by your app or temporary media files.
우리의 앱에 속해 있는 파일들만 사용자가 앱을 지울 때 지워질 수 있습니다. 파일들이 기술적으로 다른 앱이나 유저가 접근 가능하더라도 말이지요. 왜냐하면 외부 저장소에 저장 되어있기 때문이지요. 이들은 앱 밖의 다른 사용자에게 값을 제공해 주지는 않는 파일입니다. 사용자가 앱을 삭제할 때, 시스템은 외부 저장소에 있는 모든 파일을 삭제합니다. 예를 들어, 추가적인 앱이나 임시 미디어 파일로 인해 다운로드된 리소스들이 이에 해당합니다.

If you want to save public files on the external storage, use the getExternalStoragePublicDirectory() method to get a File representing the appropriate directory on the external storage. The method takes an argument specifying the type of file you want to save so that they can be logically organized with other public files, such asDIRECTORY_MUSIC or DIRECTORY_PICTURES. For example:

공개 파일을 외부 저장소에 저장하고 싶다면, getExternalStoragePublicDrectory() 메서드를 사용하세요. 외부 저장소에 적절한 티렉토리를 대표하는 File 을 획득할 수 있습니다. 메서드는 파일의 타입을 명시한 인자를 받습니다. 이 파일은 이것들이 다른 파일과 논리적으로 조합하기 위해서 저장하길 원할 수 있습니다(모참인)

public File getAlbumStorageDir(String albumName) {
    // Get the directory for the user's public pictures directory. 
    File file = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), albumName);
    if (!file.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;
}

If you want to save files that are private to your app, you can acquire the appropriate directory by callinggetExternalFilesDir() and passing it a name indicating the type of directory you’d like. Each directory created this way is added to a parent directory that encapsulates all your app’s external storage files, which the system deletes when the user uninstalls your app.

파일을 저장하기를 원한다면 (앱에서만 비공개적으로 쓰이는 파일) , 적당한 디렉토리를 획득할 수 있습니다. getExternalFilesDir() 메서드를 사용합니다. 이름을 건내줍니다. 우리가 원하는 디렉토리의 타입을 가리키는 파일이지요. 이러한 방법으로 생성된 각각의 디렉토리는 상위 폴더에 추가됩니다. 모든 앱의 외부 저장소 파일을 캡슐화 하는 디렉토리지요. 앱을 제거할 때 이 파일은 날아가게됩니다.

For example, here’s a method you can use to create a directory for an individual photo album:

예를 들어, 개별적인 포토 앨범 디렉토리를 생성하기 위해서 사용하는 메서드를 볼 수 있습니다.

public File getAlbumStorageDir(Context context, String albumName) {
    // Get the directory for the app's private pictures directory. 
    File file = new File(context.getExternalFilesDir(
            Environment.DIRECTORY_PICTURES), albumName);
    if (!file.mkdirs()) {
        Log.e(LOG_TAG, "Directory not created");
    }
    return file;
}

If none of the pre-defined sub-directory names suit your files, you can instead call getExternalFilesDir() and passnull. This returns the root directory for your app’s private directory on the external storage.

만약 미리 정의된 세부 디렉토리 이름이 우리의 파일과 일치하지 않으면, 우리는 getExternalFilesDir() 를 대신 호출 할 수 있습니다. null 을 전달해 주빈다. 이 것은 루트 디렉토리를 리턴합니다. 외부 스토리지에 있던  앱만의 디렉토리의.

Remember that getExternalFilesDir() creates a directory inside a directory that is deleted when the user uninstalls your app. If the files you’re saving should remain available after the user uninstalls your app—such as when your app is a camera and the user will want to keep the photos—you should instead usegetExternalStoragePublicDirectory().

getExternalFilesDir() 은 디렉토리를 생성합니다. 사용자가 앱을 삭제했을 때 삭제되는 디렉토리 내부에. 만약 사용자가 저장한 파일이 앱을 삭제하고 나서도 살아 있길 원한다면 (카메라 앱이고, 사용자는 사진을 지우길 바라는 것은 아니지요), getExternalStoragePublicDirectory()를 대신 사용해야 합니다.

Regardless of whether you use getExternalStoragePublicDirectory() for files that are shared or getExternalFilesDir()for files that are private to your app, it’s important that you use directory names provided by API constants likeDIRECTORY_PICTURES. These directory names ensure that the files are treated properly by the system. For instance, files saved in DIRECTORY_RINGTONES are categorized by the system media scanner as ringtones instead of music.

getExternalStoragePublicDirectory()를 사용하는 것과는 상관 없이, 디렉토리 이름을 사용하는 것은 중요합니다. API로부터 제공된 이름이지요, DIRECTORY_PICTURES 같은 이름들이요. 이러한 디렉토리 이름은 보증합니다. 파일들이 적절하게 다뤄진다는 것을요. 예를 들어 DIRECTORY_RINGTONES 에 저장된 파일은 시스템 미디어 스캐너로부터 ringtones 로 다뤄집니다. 음악이라기 보다는요

Query Free Space


If you know ahead of time how much data you’re saving, you can find out whether sufficient space is available without causing an IOException by calling getFreeSpace() or getTotalSpace(). These methods provide the current available space and the total space in the storage volume, respectively. This information is also useful to avoid filling the storage volume above a certain threshold.

얼마나 큰 데이터를 저장할 지 알기 전에, 우리는 적당한 공간이 있는지 알아볼 수 있습니다. IOException 을 나기 전에 알아볼 수 있습니다. getFreeSpace()나 getTotalSpace() 메서드를 호출함으로써요. 이러한 메서드는 현재 사용가능한 공간을 알려줍니다. 비교적, 이 정보는 유용합니다. 일정 수준 미만으로 공간을 채우는 데에 .

However, the system does not guarantee that you can write as many bytes as are indicated by getFreeSpace(). If the number returned is a few MB more than the size of the data you want to save, or if the file system is less than 90% full, then it’s probably safe to proceed. Otherwise, you probably shouldn’t write to storage.

하지만, 시스템은 보증하지는 않습니다. getFreeSpace()로 알게된 정보를  얼만큼 쓸 수 있다는 것인지는. 만약 이 숫자가 우리가 저장하고 싶은 파일의 크기보다 단지 몇 MB 밖에 차이가 없다면, 혹은 파일 시스템이 90% 미만이라면, 안전하게 진행됩니다.  (다시 번역 할게요). 아니면 스토리지에 쓰면 안됩니다.

Note: You aren’t required to check the amount of available space before you save your file. You can instead try writing the file right away, then catch an IOException if one occurs. You may need to do this if you don’t know exactly how much space you need. For example, if you change the file’s encoding before you save it by converting a PNG image to JPEG, you won’t know the file’s size beforehand.

주의: 파일을 쓰기 전에 사용 가능한 공간을 체크하라고 요구받지는 않습니다. 대신, 파일을 쓰는 try 를 해보고, IOException 이 발생 시 catch 할 수 있습니다. 우리가 정확하게 얼마나 우리가 공간을 원하는지 알지 못할 때 이러한 방법을 쓸 수 있습니다. 예를 들어,  파일을 인코딩 하는데, 우리가 변환 파일을 저장하기 전에, 우리는 얼마나 될 지 모르지요.

Delete a File


You should always delete files that you no longer need. The most straightforward way to delete a file is to have the opened file reference call delete() on itself.

필요 없을 때 파일을 지워야 합니다. 가장 직접적인 방법은 delete() 를 부르는 것입니다.

myFile.delete();

If the file is saved on internal storage, you can also ask the Context to locate and delete a file by callingdeleteFile():

내부 저장소에 파일이 저장되어 있다면, 우리는 또한 Context 를 요청할 수 있습니다. deleteFile()을 호출함으로써요.

myContext.deleteFile(fileName);

Note: When the user uninstalls your app, the Android system deletes the following:

  • All files you saved on internal storage
  • All files you saved on external storage using getExternalFilesDir().

However, you should manually delete all cached files created with getCacheDir() on a regular basis and also regularly delete other files you no longer need.

하지만 우리는 수동적으로 모든 캐시 파일을 지워줘야 합니다. getCacheDir() 를 이용해서요.

Advertisements

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중