NodeStream
Processing Stream
노드스트림, 프로세스 스트림을 사용하는 자바의 방식과 같음
private lateinit var file: File
file = File(filesDir, "data.txt")
저장할 파일은 위와 같이 선언한다.
filesDir은 context가 제공하는 것으로 data/data/패키지/files에 data.txt라는 이름으로 들어갈 것이다.
이 파일은 사용자가 접근 할 수 없다
private fun saveFile(){
try {
// use: try use resource
BufferedWriter(FileWriter(file, true)).use {
it.append("지금 시각은 ${Date()} 입니다.\n")
}
statusTV.text = "저장 완료"
}catch(e:IOException){
Log.e(TAG, "saveFile: ", e)
}
}
파일을 저장하는 코드이다.
use를 쓰면 writer사용이 끝나고 자동으로 close해준다.
private fun loadFile(){
Log.d(TAG, "file: ${file.canonicalPath}")
try {
//useLines : BufferedReader로 한줄씩 읽어서 처리. 모두 읽으면 close한다.
BufferedReader(FileReader(file)).useLines {
//fold : 초기값을 설정하고 요소의 첫번째 부터 람다식 오른쪽의 누적값으로 적용하여 accu가 되고, 다음값으로..
var data =it.fold(""){
accu, now ->
"$accu\n$now"
}
Log.d(TAG, "loadFile: $data")
statusTV.text = data
}
}catch(e:IOException){
Log.e(TAG, "loadFile: ", e)
}
}
fold는 데이터들을 순차적으로 누적하여 더해주는 역할을 한다.
https://velog.io/@blucky8649/%EC%BD%94%ED%8B%80%EB%A6%B0-reduce-fold-%ED%95%A8%EC%88%98
다른 kt 파일 등은 바이트코드로 변환되어 저장되지만assets 폴더 내의 파일은 txt파일 자체를 그대로 처리하도록 해준다.
private fun loadAssets(){
try{
BufferedReader(InputStreamReader(assets.open("data.txt"))).useLines {
var data =it.fold(""){
accu, now ->"$accu\n$now"
}
Log.d(TAG, "loadFile: $data")
statusTV.text = data
}
}catch(e:IOException){
Log.e(TAG, "onCreate: assets 파일 로딩 실패", e)
}
}
assets키워드는 assetManager가 관리하며 asset 폴더에 접근할 수 있게 해준다. 이를 통해
assets내의 data.txt 파일을 읽을 수 있다.
사용자가 직접 파일에 접근하여 읽을 수 있도록 외부저장소에 파일을 저장할 수도 있다.
externalBtn.setOnClickListener {
Log.d(TAG, "현재 미디어의 상태 ${Environment.getExternalStorageState()}")
Log.d(TAG, "외장 메모리 경로: ${getExternalFilesDir(null)}") // null: 시스템 default 경로 리턴.
if(Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED){
val file = File(getExternalFilesDir(null), "data.txt")
try{
//FileWriter(file, true) 이면 기존파일에 추가.
BufferedWriter(FileWriter(file)).use {
it.append("외부 저장소에 write 하기")
}
BufferedReader(FileReader(file)).useLines {
//fold : 초기값을 설정하고 요소의 첫번째 부터 람다식 오른쪽의 누적값으로 적용하여 accu가 되고, 다음값으로..
val lines = it.fold(""){
accu, now ->"$accu\n$now"
}
statusTV.text = lines
}
}catch(e: IOException){
Log.e(TAG, "onCreate: 외장 메모리 사용 실패", e)
}
}else{
Toast.makeText(this, "이 기기는 외장 메모리를 지원하지 않습니다.", Toast.LENGTH_SHORT).show()
}
}
}
D/FileOutActivity싸피: 현재 미디어의 상태 mounted
D/FileOutActivity싸피: 외장 메모리 경로: /storage/emulated/0/Android/data/com.ssafy.ui6/files
sybolic link 경로 : mnt > sdcard> Android> data> 패키지>files>data.txt
파일 위치 확인을 해보면
외장 메모리 경로 로그가 나오는 곳에도 있고 위의 경로에도 파일이 있는데, 이유는 symbolic link로 sd card 가 있는 것처럼 파일 경로가 표출되기 때문이다.