[Android] 파일 입출력

2 분 소요

Intro

🙋‍♀️ 이번 포스팅에서는 파일 입출력에 관해 작성해보고자 한다!

안드로이드 데이터 저장소는 크게 2가지로 나뉜다.

1. 내부 저장소: 애플리케이션을 통해서만 접근 가능하다.

  • 용량이 작다.

2. 외부 저장소: 단말기 내부 고유 영역이 존재해 모든 애플리케이션에서 접근 가능하다.

  • 용량이 크다.
  • scoped storage 정책

👩 그렇다면 scoped storage 정책에 대해서 조금 더 자세히 살펴보자!

🙋‍♀️ scoped storage 정책

  1. 앱 데이터 폴더
    • 읽고 쓰기 권한 필요하지 않다.
    • 해당 app에서만 접근이 가능하다.
    • app 삭제 시, 함께 삭제된다.
  2. 미디어 파일들: 사진, 동영상, 음원 파일 저장소

  3. 공용 파일들
    • Downloads 폴더에 저장된다.
    • 모든 app에서 접근이 가능하다. (파일 관리자 어플을 통해 사용자가 선택한 파일이 대상!)


이번 포스팅에서는 내부 저장소, 앱 데이터 폴더, 공용 파일 폴더 세가지를 살펴볼 것이다.

🙋‍♀️내부 저장소

  • openFileOutput, openFileInput
    • in/output stream을 얻어와 사용한다.

1. openFileOutput을 통해 내부 저장소에 데이터 저장!

  val fos = openFileOutput("data1.dat", Context.MODE_PRIVATE)
  val dos = DataOutputStream  

  dos.writeInt(10)
  dos.writeBoolean(true)
  dos.writeUTF("test1")

  dos.flush()
  dos.close() 
  • MODE_PRIVATE: 덮어 씌우기
    • MODE_APPEND: 이어서 쓰기


2. openFileInput을 통해 내부 저장소 데이터 읽기!

  val fis = openFileInput("data1.dat")
  val dis = DataInputStream(fis)

  val data1 = dis.readInt()
  val data3 = dis.readBoolean()
  val data4 = dis.readUTF()

  dis.close()


🙋‍♀️외부 저장소: 앱 데이터 폴더

  • FileInputStrea, FileOutputStream 사용
    • 앱 데이터 폴더 경로를 사용한다.

1. 앱 데이터 폴더 경로 가져오기!

file_path = getExternalFilesDir(null).toString()
  • null을 지정할 경우, 앱 데이터 폴더 경로가 반환된다.
  • ‘ENVIRONMENT.____‘로 특정 폴더를 지정할 경우, 해당 폴더의 경로가 반환된다.


2. 앱 데이터 폴더에 데이터 저장!

  val fos = FileOutputStream("$file_path/data2.dat")
  val dos = DataOutputStream(fos)

  dos.writeInt(20)
  dos.writeBoolean(false)
  dos.writeUTF("test2")

  dos.flush()
  dos.close()


3. 앱 데이터 폴더에서 데이터 읽어오기!

  val fis = FileInputStream("$file_path/data2.dat")
  val dis = DataInputStream(fis)

  val data1 = dis.readInt()
  val data3 = dis.readBoolean()
  val data4 = dis.readUTF()

  dis.close()


🙋‍♀️외부 저장소: 공용 파일

  • 파일 관리 앱의 액티비티를 이용한다.

1. 파일을 만들어 사용하기 위해 파일 관리 앱 액티비티 실행!

  val fileIntent = Intent(Intent.ACTION_CREATE_DOCUMENT)

  fileIntent.addCategory(Intent.CATEGORY_OPENABLE)

  fileIntent.type = "*/*"

  startActivityForResult(fileIntent, 100)
  • Intent로 파일 관리 앱 액티비티를 실행한다.
    • ACTION_CREATE_DOCUMENT: 파일을 만들어 사용하기 위한 용도
    • CATEGORY_OPENABLE: 파일을 열 수 있도록 지정
    • 열어 볼 타입 지정
      • ‘image/*’: 모든 이미지 파일


  • Intent 실행 결과로 사용자가 지정한 파일에 대해서 해당 코드 실행! (쓰기 실행)

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
            super.onActivityResult(requestCode, resultCode, data)
    
            if(requestCode == 100) {
                if (resultCode == RESULT_OK) {
                    // 핵심!
                    // w: 쓰기 모드로 사용
                    val des1 = contentResolver.openFileDescriptor(data?.data!!, "w")
                      
                    val fos = FileOutputStream(des1?.fileDescriptor)
                    val dos = DataOutputStream(fos)
    
                    dos.writeInt(300)
                    dos.writeBoolean(true)
                    dos.writeUTF("test3")
    
                    dos.flush()
                    dos.close()
                }
            }
    }
    


공용 파일을 읽기 위해 파일 관리 앱 액티비티 실행!

  val fileIntent = Intent(Intent.ACTION_OPEN_DOCUMENT)

  fileIntent.type = "*/*"

  startActivityForResult(fileIntent, 200)
  • ACTION_OPEN_DOCUMENT: 데이터를 읽어 오는 용도


  • Intent 실행 결과로 사용자가 지정한 파일에 대해서 해당 코드 실행! (읽기 실행)
    • onActivityResult 코드에 이어서 작성!
  }else if(requestCode == 200){
      if(resultCode == RESULT_OK) {
        # 핵심!
        # r: 읽기 모드로 사용
          val des2 = contentResolver.openFileDescriptor(data?.data!!, "r")
          val fis = FileInputStream(des2?.fileDescriptor)
          val dis = DataInputStream(fis)

          val data1 = dis.readInt()
          val data3 = dis.readBoolean()
          val data4 = dis.readUTF()

          dis.close()
      }
  }

📃참고

  • 인프런 윤재성의 Kotlin 기반 안드로이드 앱 개발 Part3 수강

댓글남기기