안드로이드 코틀린 : 앱 디렉토리 폴더 생성, 탐색, 삭제
Lucy Archive
Lucy / Facilitate4U
2021. 3. 24. 01:07

Android Kotlin : 폴더 생성, 탐색, 삭제

이번 포스트는

File 클래스 기본 사용법에 대해 알아보고, 앱 전용 디렉토리에서 폴더 생성, 탐색, 삭제 하는 기능에 대해 정리

하였습니다. 이 포스트에는 저장소의 개념과 AlertDialog 사용법을 포함하고 있어 필요하신 분은 아래의 링크를 참조해주세요.

안드로이드 저장소 정리

 

안드로이드 저장소 정리 : 앱 전용 디렉토리? 내부 저장소? 외부 저장소? 공용저장소

안드로이드 저장소 정리 안드로이드 앱 전용 디렉토리, 내부 저장소, 외부 저장소, 공용 저장소에 대한 용어 혼동이 있어 정리하였습니다. 세부 내용들이 필요하면 추가할 예정입니다. 용어 글

juahnpop.tistory.com

AlertDialog 기본 사용법

 

안드로이드 코틀린 : AlertDialog 기본, 목록, 라디오 버튼, 체크 박스, EditText 입력 창

안드로이드 코틀린 : AlertDialog 기본, 목록, 체크박스 목록, 라디오 버튼 목록, 입력(Edit Text) 사용법 이번 포스트는 안드로이드 코틀린 언어를 사용하여 AlertDialog를 활용한 기본 사용 방법, 목록 선

juahnpop.tistory.com

 

기본 사용법

저장소 경로 불러오기

  • 앱 전용 디렉토리(내부저장소) : getFilesDir()
  • 앱 전용 디렉토리(외부저장소) : getExternelFilesDir()

File 클래스 기본 사용법

File 클래스에서 주로 사용되는 사용법은 아래와 같이 코드로 정리하였습니다.

// File 클래스 인스턴스 만들기
val file = File("PATH") // 전체 경로를 입력

// 파일 또는 폴더 존재 유무 확인
if(file.exists()) {
	println("파일이 존재합니다")
}

// file 이 파일인지 폴더 인지 확인
if(file.isFile) {
	println("파일입니다.")
}
if(file.isDirectory) {
	println("폴더입니다.")
}

// 폴더 또는 파일 생성
if(!file.isFile) {
	file.createNewFile()
}
if(!file.exists()) {
	file.mkdirs()
}

// 파일 또는 디렉토리 삭제
file.delete()

// 파일 이름 반환
val fileName = file.name

// 파일 절대 경로 반환
val filePath = file.absolutePath

※ File 클래스는 파일을 읽고 쓰는 기능은 포함되어 있지 않습니다. 파일을 읽고 쓰기 위해서는 Stream이라는 클래스를 사용해야 합니다.

 

프로젝트 생성 및 환경설정

프로젝트 생성

아래 그림과 같이 프로젝트를 생성합니다.

  • 프로젝트명 : ManagingFolder
  • 사용 언어 : Kotlin

프로젝트 생성

 

ViewBinding 설정

build.gradle(Module: ManagingFolder) 파일에 아래의 ViewBinding 설정 코드를 추가합니다. 

android { 
	...
    viewBinding { 
    	enabled = true 
    } 
}

코드 추가가 완료되면 아래와 같이 Sync Now 클릭해서 Gradle 변경 사항을 적용합니다.

viewBinding 설정 코드 추가 및 적용

ViewBinding 은 Layout 에 있는 View의 Id를 코틀린 코드에서 직접 사용 할 수 있게 해주는 도구입니다. View Binding과 관련된 설명은 아래의 링크를 참조해주세요.

안드로이드 View Binding 사용하기

 

안드로이드 View Binding 사용하기 - kotlin-android-extensions 지원 중단

안드로이드 View Binding 방법 정리 안드로이드 코드에서 레이아웃 View에 접근하기 위해 사용된 kotlin-android-extensions 의 지원이 중단예정으로, 이를 대체하여 사용 할 수 있는 ViewBinding 사용법에 대해

juahnpop.tistory.com

 

레이아웃 작성

activity_main.xml 코드 작성

activity_main.xml 레이아웃 파일에 아래와 같이 4개의 버튼과 1개의 텍스트뷰 등록 코드를 작성합니다. 버튼과 텍스트 뷰의 기능은 아래와 같습니다.

  • Show App Directory Path 버튼: 앱 디렉토리 절대 경로 보여주기
  • Make Directory 버튼 : 앱 디렉토리에 특정 이름 폴더 추가
  • Load FileLists 버튼 : 앱 디렉토리의 파일 리스트 TextView에 출력
  • Delete Directory 버튼 : 앱 디렉토리의 특정 이름 폴더 삭제
  • TextView : Load FileLists 버튼을 누르면 앱 디렉토리의 파일 리스트 출력
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btnGetDir"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:text="Show App Directory Path"
        android:textAllCaps="false"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btnMkdir"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:text="Make Directory"
        android:textAllCaps="false"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btnGetDir" />

    <Button
        android:id="@+id/btnFileList"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:text="Load FileLists"
        android:textAllCaps="false"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btnMkdir" />

    <Button
        android:id="@+id/btnDeleteDir"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:text="Delete Directory"
        android:textAllCaps="false"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btnFileList" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="FileList"
        android:textSize="20sp"
        android:layout_margin="8dp"
        app:layout_constraintBottom_toBottomOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

레이아웃 미리보기

코틀린 코드 작성

앱 전용 디렉토리 경로 불러오기

앱 전용 디렉토리는 앱 마다 생성되는 별도의 디렉토리 입니다. 앱은 기본적으로 내부저장소의 /data/data/{package_name} 경로에 저장됩니다. /data/data/{package_name} 경로는 내부적으로 /data/user/0/{package_name} 경로와 연결되어 있습니다. 앱 전용 디렉토리를 불러오기 위해 아래와 같이 코드를 작성합니다. 

package com.blacklog.managingfolder

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import com.blacklog.managingfolder.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)

        binding.btnGetDir.setOnClickListener {
            toast(filesDir.toString())
        }
    }

    fun toast(message:String){
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
    }
}

ViewBinding 설정 코드가 있어 불 필요하게 코드가 길지만, filesDir만 사용하여 앱 전용 디렉토리를 간단하게 불러 올 수 있습니다. filesDirgetFilesDir() 의 반환값입니다.

Show App Directory Path 버튼 동작 결과

디렉토리 생성

UI의 Make Directory 버튼을 누르면 EditText가 포함된 AlertDialog에서 폴더명을 입력받아 새 폴더를 추가하는 방식으로 코드를 작성하였습니다. EditText가 포함된 AlertDialog를 만들기 위해 아래와 같이 레이아웃 파일을 추가하고 코드를 작성합니다.

alertdialog_edittext.xml 생성

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="22dp"
        android:layout_marginEnd="22dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity.kt 의 onCreate() 함수내에 아래의 버튼 리스너 코드를 추가합니다.

package com.blacklog.managingfolder

import android.content.DialogInterface
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import com.blacklog.managingfolder.databinding.ActivityMainBinding
import com.blacklog.managingfolder.databinding.AlertdialogEdittextBinding
import java.io.File

class MainActivity : AppCompatActivity() {

    lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)

        binding.btnGetDir.setOnClickListener {
            toast(filesDir.toString())
        }
        binding.btnMkdir.setOnClickListener {
            val alertDialogEditText = AlertdialogEdittextBinding.inflate(layoutInflater)
            val builder = AlertDialog.Builder(this)
                .setTitle("Input Directory Name")
                .setView(alertDialogEditText.root)
                .setPositiveButton("OK"){ dialogInterface: DialogInterface, i: Int ->
                    makeDirectory(alertDialogEditText.editText.text.toString())
                }
                .show()
        }
    }

    fun makeDirectory(folderName:String){
        val path = File("$filesDir/$folderName")
        if(!path.exists()){
            path.mkdirs()
        }else{
            toast("$folderName is exists")
        }
    }

    fun toast(message:String){
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
    }
}

위 코드를 빌드후 Make Directory 버튼을 클릭하면 아래 그림과 같이 AlertDialog를 통해 입력 받은 폴더 이름이 앱 전용 디렉토리의 files 폴더에 추가된 것을 확인 할 수 있습니다. 

Make Directory 버튼 실행화면과 추가된 폴더 확인

파일 리스트 보기

Load FileLists 버튼을 누르면 앱 전용 디렉토리의 files 폴더에 있는 파일 및 폴더 리스트를 TextView에 출력합니다. 기능을 추가하기 위해 MainActivity.kt 파일의 onCreate() 함수내에 아래의 버튼 리스너 코드를 추가합니다.

binding.btnFileList.setOnClickListener {
    binding.textView.text = null
    val path = File(filesDir.toString())
    val files = path.listFiles()
    var strFileList: String? = "App Directory File Lists\n"
    for(file in files){
        strFileList += "->" + file.name + "\n"
    }
    binding.textView.text = strFileList
}

위 코드를 추가하고 실행 후 Load FileLists 버튼을 클릭하면 파일리스트가 하단의 TextView에 출력됩니다.

Load FileLists 버튼 실행 결과

디렉토리 삭제하기

디렉토리 삭제 기능은 지난 포스트에서 소개한 AlertDialog의 체크박스 기능으로 구현하였습니다. 파일 및 폴더 리스트를 체크 박스 리스트로 등록 후 선택된 항목은 삭제하는 코드입니다. 이 기능을 추가하기 위해 MainActivity.kt에 아래의 버튼 리스너 코드를 추가합니다.

binding.btnDeleteDir.setOnClickListener {
    val files = File(filesDir.toString()).listFiles()
    val selectedItemIndex = ArrayList<Int>()
    var filesName = Array(files.size) { item -> "" }
    for(i in files.indices){
        filesName[i] = files[i].name
    }
    val builder = AlertDialog.Builder(this)
        .setTitle("삭제할 디렉토리 선택")
        .setMultiChoiceItems(filesName, null){ dialogInterface: DialogInterface, i: Int, b: Boolean ->
            if(b){
                selectedItemIndex.add(i)
            }else if(selectedItemIndex.contains(i)){
                selectedItemIndex.remove(i)
            }
        }
        .setPositiveButton("삭제"){ dialogInterface: DialogInterface, i: Int ->
            for(i in selectedItemIndex.indices){
                val file = File("$filesDir/${filesName[selectedItemIndex[i]]}")
                file.delete()
            }
        }
    val dialog = builder.create()
    dialog.show()
}

AlertDialog 빌더를 사용하여 체크 박스 목록을 만들어 이벤트 처리하는 방법은 하단의 관련포스트를 참고해주세요. 위 코드를 작성 후 실행하면 Delete Directory 버튼 클릭시 아래와 같이 동작합니다. 

Delete Directory 버튼 실행 화면

끝까지 읽어 주셔서 감사합니다.^^

관련포스트

🤞 안드로이드(코틀린) 앱 제작하기 관련글 목록 보기

🤞 안드로이드(코틀린) 팝업, 다이얼로그 관련글 목록 보기

🤞 안드로이드(코틀린) 파일 및 폴더 관련글 목록 보기

🤞 안드로이드(코틀린) 저장소 관련글 목록 보기