반응형
내가 싫어하는 입출력....그래도 해야지 어쩌겠어....
파일 입출력
- 안드로이드는 애플리케이션의 데이터 저장소를 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 |