[안드로이드/데이터 관리] 파일 입출력

2023. 4. 29. 00:27· Android
목차
  1. 파일 입출력
  2. Scoped Storage
반응형

내가 싫어하는 입출력....그래도 해야지 어쩌겠어....

파일 입출력

  • 안드로이드는 애플리케이션의 데이터 저장소를 2개 제공
    • 내부 저장소 : 애플리케이션 통해서만 접근 가능 -> openFileOuput / openFileInput 메서드 사용 *용량 적고, 사용자도 열람X
    • 외부 저장소 : 단말기 내부에서 사용하는 공유 영역 (단말기 저장소), 컴퓨터에 단말기 연결시 탐색기로 접근하는 영역을 의미 -> FileInputStream / FileOutputStream 메서드 사용
  • 안드10의 외부 저장소 -> 모든 앱이 접근할 수 있다보니 보안 문제 발생해 외부저장소에 제한을 둠 -> 안드10에서는 옵션으로 제한을 선택할 수 있도록 했는데 안드11부터는 옵션 없어지고 자유로운 접근 불가능 (Scoped Storage)

Scoped Storage

*전부 외부 저장소인데 제한을 둬서 접근 가능한 저장소만 나열

  • 앱 데이터 폴더 : 읽고 쓰는데 권한 필요 없고 해당 앱만 접근 가능, 앱 삭제시 폴더도 삭제  *용량 크기, 숨긴파일로 되어있음
  • 미디어 파일 : 사진, 동영상, 음원 저장
  • 공용 파일 : Downloads 폴더 -> 모든 앱이 접근할 수 있음. 하지만 코드를 통한 직접 접근은 불가능하고 단말기에 설치된 파일 관리 어플을 통해서만 접근. 즉, 파일 관리 어플을 실행해 사용자가 직접 파일을 선택해줘야 함 (단말기 주인만 접근 가능)
class MainActivity : AppCompatActivity() {

    private lateinit var binding:ActivityMainBinding
    lateinit var file_path: String

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater) // 뷰바인딩 객체
        val view = binding.root //뷰바인딩을 통해 레이아웃과 뷰가 결합 -> .root 를 통해 View 객체만를 뽑아내는(?)
        setContentView(view)

        // 외부저장소 경로
        file_path = getExternalFilesDir(Environment.DIRECTORY_MUSIC).toString()
        // null -> 앱만 사용 가능한 데이터폴더를 얻어옴, Environment.DIRECTORY종류 -> 해당 경로를 얻어옴
        Log.d("test",file_path)

        // 내부 저장소는 용량이 작음 -> 과거엔 sd 카드(외부저장소)를 꽂아 사용했지만 현재는 기술이 좋아져서 그냥 플래시 메모리 하나로 단말기 내부에서 다 처리
        // 용량 작고 외부로 유출X 데이터 -> 내부저장소 / 용량 크면 -> 외부저장소(downloads) / 용량 커도 유출X 데이터 -> 앱에 할당된 외부 저장소 영역(앱에서만 접근한 공간)

        // 내부 저장소 저장
        binding.button.setOnClickListener {

            val fos = openFileOutput("data1.dat", Context.MODE_PRIVATE)  //데이터를 쓸 파일을 열기
            // mode : MODE_PRIVATE (덮어씌우기), MODE_APPEND(이어서쓰기)
            val dos = DataOutputStream(fos)
            //데이터 쓰기
            dos.writeInt(100)
            dos.writeDouble(11.11)
            dos.writeBoolean(true)
            dos.writeUTF("문자열1")

            dos.flush() //stream에 남아 있는 데이터를 강제로 내보냄
            dos.close()

            binding.textView.text = "내부 저장소 쓰기 완료"
        }

        binding.button2.setOnClickListener {

            val fis = openFileInput("data1.dat")  //데이터를 읽을 파일 열기
            val dis = DataInputStream(fis)

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

            dis.close()

            binding.textView.text = "data1: ${data1}\n"
            binding.textView.append("data2: ${data2}\n")
            binding.textView.append("data3: ${data3}\n")
            binding.textView.append("data4: ${data4}")
        }

        // 외부 저장소 저장
        binding.button3.setOnClickListener {
            val fos = FileOutputStream("${file_path}/data2.dat")
            val dos = DataOutputStream(fos)

            dos.writeInt(300)
            dos.writeDouble(33.33)
            dos.writeBoolean(true)
            dos.writeUTF("문자열2")

            dos.flush()
            dos.close()

            binding.textView.text = "외부 저장소의 앱 데이터 폴더에 저장 (쓰기 완료)"
        }

        binding.button4.setOnClickListener {
            val fis = FileInputStream("${file_path}/data2.dat")
            val dis = DataInputStream(fis)

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

            dis.close()

            binding.textView.text = "data1: ${data1}\n"
            binding.textView.append("data2: ${data2}\n")
            binding.textView.append("data3: ${data3}\n")
            binding.textView.append("data4: ${data4}")

        }

        binding.button5.setOnClickListener {
            // 파일 관리 앱의 액티비티 실행
            val fileIntent = Intent(Intent.ACTION_CREATE_DOCUMENT)  // 파일을 만들어 쓰는 옵션 줌
            fileIntent.addCategory(Intent.CATEGORY_OPENABLE) //비로소 쓰기 위한 파일을 열 수 있음

            //mine type -> 어떠한 파일을 볼지 지정 (구글에 mine type 찾아보면 많이 나옴)
            fileIntent.type = "*/*" //전체
            //fileIntent.type = "image/*" //이미지만
            activityResultLauncher1.launch(fileIntent) //다운로드 파일 열리고 파일 이름을 적고 저장하면 그 파일에 접근할 수 있는 경로 넘어옴


        }

        binding.button6.setOnClickListener {
            // 파일 관리 앱의 액티비티 실행
            val fileIntent = Intent(Intent.ACTION_OPEN_DOCUMENT)  // 파일을 만들어 쓰는 옵션 줌
            fileIntent.type = "*/*"
            activityResultLauncher2.launch(fileIntent)

        }

    }

    private val activityResultLauncher1 : ActivityResultLauncher<Intent> =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult())
        {

            when (it.resultCode) {
                RESULT_OK -> {
                    //파일의 경로를 관리하는 객체를 얻어옴
                    val des1 = contentResolver.openFileDescriptor(it.data?.data!!,"w") // it.data?.data!!(사용자가 쓰기를 원하는 파일의 경로)를 가지고 file descriptor를 만듬
                    val fos = FileOutputStream(des1?.fileDescriptor) //파일 접근 스트림 생성
                    val dos = DataOutputStream(fos)

                    dos.writeInt(500)
                    dos.writeDouble(55.55)
                    dos.writeBoolean(true)
                    dos.writeUTF("문자열3")

                    dos.flush()
                    dos.close()

                    binding.textView.text = "다운로드 폴더에 저장"
                }

            }

        }

    private val activityResultLauncher2 : ActivityResultLauncher<Intent> =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult())
        {


            when (it.resultCode) {

                RESULT_OK -> {
                    val des2 = contentResolver.openFileDescriptor(
                        it.data?.data!!,
                        "r"
                    ) // it.data?.data!!(사용자가 쓰기를 원하는 파일의 경로)를 가지고 file descriptor를 만듬
                    val fis = FileInputStream(des2?.fileDescriptor) //파일 접근 스트림 생성
                    val dis = DataInputStream(fis)

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

                    dis.close()

                    binding.textView.text = "data1: ${data1}\n"
                    binding.textView.append("data2: ${data2}\n")
                    binding.textView.append("data3: ${data3}\n")
                    binding.textView.append("data4: ${data4}")

                }

            }
        }
}

 

반응형

'Android' 카테고리의 다른 글

[안드로이드/데이터입출력] assets  (0) 2023.04.29
[안드로이드/데이터 관리] Raw 파일 읽어오기  (0) 2023.04.29
[안드로이드/데이터 관리] Application Class  (0) 2023.04.29
[안드로이드/데이터입출력] 코드를 이용해 View 객체 생성  (0) 2023.04.29
[안드로이드/데이터입출력] XML을 이용해 View 객체 생성  (0) 2023.04.29
  1. 파일 입출력
  2. Scoped Storage
'Android' 카테고리의 다른 글
  • [안드로이드/데이터입출력] assets
  • [안드로이드/데이터 관리] Raw 파일 읽어오기
  • [안드로이드/데이터 관리] Application Class
  • [안드로이드/데이터입출력] 코드를 이용해 View 객체 생성
gangmini
gangmini
gangmini
게으른J 의 테크로그
gangmini
전체
오늘
어제
글쓰기방명록관리자
  • 분류 전체보기 (127)
    • 인공지능(AI) & 데이터 분석 (5)
    • Android (91)
      • Coroutine (3)
      • Compose (0)
      • 안드로이드 CS (0)
    • Kotlin (3)
    • Data Structure (0)
    • 알고리즘 (20)
      • 알고리즘 이론 (11)
      • 백준(BOJ) 문제 풀이 (9)
    • Build Tool (2)
    • Git (2)
    • 일본어 (0)
    • 기타(취준, 활동) (0)


인기 글



최근 댓글



최근 글

hELLO · Designed By 정상우.v4.2.2
gangmini
[안드로이드/데이터 관리] 파일 입출력
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.