Android: 파일 입출력

Beautify.log·2022년 2월 10일
0

Android with Kotlin

목록 보기
14/17
post-thumbnail

개요


파일 입출력이란?

파일 입출력은 말 그대로 디바이스에 파일로 저장하고 그 파일을 뷰에 출력해주는 일련의 과정을 말합니다.


파일 입출력 구현을 위한 레이아웃


레이아웃

우선 화면단에서 파일 입출력을 보여주기 위해 레이아웃을 만들어줍니다.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    <EditText
            android:id="@+id/editText"
            android:layout_width="494dp"
            android:layout_height="48dp"
            android:inputType="textPersonName"
            android:ems="10"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintVertical_bias="0.172"
    />
    <Button
            android:id="@+id/read"
            android:text="읽기"
            android:layout_width="323dp"
            android:layout_height="49dp"
            app:layout_constraintBottom_toTopOf="@+id/write"
            android:layout_marginBottom="48dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/editText"
            app:layout_constraintHorizontal_bias="0.501"
            app:layout_constraintVertical_bias="1.0"
    />
    <Button
            android:id="@+id/write"
            android:text="쓰기"
            android:layout_width="323dp"
            android:layout_height="49dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintBottom_toTopOf="@+id/clear"
            app:layout_constraintHorizontal_bias="0.501"
            android:layout_marginBottom="52dp"/>
    <Button
            android:id="@+id/clear"
            android:text="CLEAR"
            android:layout_width="323dp"
            android:layout_height="49dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.501"
            android:layout_marginBottom="360dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>

버튼 클릭 시 파일 읽고 쓰기, 뷰에 출력


코드를 뜯어가며 하나씩 살펴보겠습니다.

import android.os.Bundle
import android.provider.ContactsContract.Intents.Insert.NOTES
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import java.io.*
import java.lang.Exception

class MainActivity : AppCompatActivity(), View.OnClickListener {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val read = findViewById<Button>(R.id.read)
        val write = findViewById<Button>(R.id.write)
        val clear = findViewById<Button>(R.id.clear)

        read.setOnClickListener(this)
        write.setOnClickListener(this)
        clear.setOnClickListener(this)
    }

우선은 뷰에 있는 버튼 세개를 가져옵니다. 각각의 버튼은 클릭 이벤트 리스너가 걸립니다.

    override fun onClick(view: View?) {
        val edit = findViewById<EditText>(R.id.editText)

        if(view?.id == R.id.read) {
            var reader:BufferedReader? = null

            try {
                val `in`: InputStream? = openFileInput(NOTES)

                if (`in` != null) {
                    reader = BufferedReader(InputStreamReader(`in`))
                    var str: String?
                    val buf = StringBuffer()

                    // 파일 읽기
                    while (reader.readLine().also { str = it } != null) {
                        println("$str")
                        buf.append("""$str""")  // 실제로 값을 읽는 위치
                    }

                    edit.setText(buf.toString())
                }
            } catch (e:FileNotFoundException) {
                // e.printStackTrace()
                println(e.message)
                println("파일을 찾을 수 없음")
            } catch (e:Exception) {
                e.printStackTrace()
                Toast.makeText(this, "exception: $e", Toast.LENGTH_SHORT).show()
            } finally {
                if(reader != null)
                    try { reader.close() }
                    catch (e:Exception) { e.printStackTrace() }
            }

메인 클래스가 View.OnClickListener를 상속받으므로 onClick 함수가 구현되어야 합니다.

view를 매개변수로 받아서 이 변수의 아이디가 위에서 선언한 버튼인 경우에 대해 조건식을 세워줍니다.

우선 읽기입니다.

BufferedReader를 준비해줍니다. 그 다음으로 InputStream을 `in`으로 잡아주었습니다. 백틱을 붙여준 이유는 예약어를 변수명으로 사용하기 위함입니다.

InputStream은 입력된 데이터를 빨아들이는 것으로 보면 됩니다.

이 때 파일을 스트림으로 읽기 위해 openFileInput을 사용하였습니다. NOTES는 파일 이름입니다.

읽어들인 파일이 null이 아닐 때 BufferedReader로 파일을 읽어주고 읽은 내용을 저장할 변수 str을 준비합니다.

그리고 문자열의 추가/변경을 위해 StringBuffer도 준비해줍니다.

줄단위로 문장을 읽으면서 strwhile루프를 돌며 문장을 추가해주는데, 이것이 null이 아닐 때, 즉 문장이 입력 되어있을 때

StringBuffer에 값을 추가해줍니다.

저장된 값을 텍스트입력창에 뿌려줍니다.

기본적으로 파일 입출력은 예외발생 사항이 있을 수 있기 때문에 try catch 처리를 해주는 것이 좋습니다.

        } else if (view?.id == R.id.write) {
            var out:OutputStreamWriter? = null

            try {
                // MODE_PRIVATE : 덮어쓰기, MODE_APPEND : 이어쓰기
                out = OutputStreamWriter(openFileOutput(NOTES, MODE_PRIVATE))
                out.write(edit.text.toString())     // 실제로 값을 써줌

                Toast.makeText(this, "데이터 저장", Toast.LENGTH_SHORT).show()
            } catch (e:Exception) {
                e.printStackTrace()
            } finally {
                if (out != null) try {
                    out.close()
                } catch (e:IOException) { e.printStackTrace() }
            }

        } else if (view?.id == R.id.clear) {
            edit.setText("")
        }
    }
}

write 버튼을 눌렀을 때 처리할 작업입니다.
스트림으로 파일을 써내려갈 OutputStreamWriter를 준비해줍니다.

그리고 파일을 읽어서 써주기 위해 openFileOutput을 사용하고 매개변수로 파일 이름과 MODE_PRIVATE이라는 덮어쓰기 기능을 넣어줍니다.

데이터가 저장되었다면 토스트를 띄워 데이터 저장에 성공했음을 알려줍니다.

profile
tried ? drinkCoffee : keepGoing;

0개의 댓글