룬아님의 취중코딩

(파일 다루기 3) URI로 real path 가져오기 본문

개발/안드로이드 개발

(파일 다루기 3) URI로 real path 가져오기

룬아님 2019. 10. 11. 17:42

SAF로 파일을 불러오거나 파일을 수정할 때에는 URI를 사용합니다.
하지만 개발 요구에 따라 URI가 아닌 실제 저장 위치를 알아야 할 때가 있습니다.

이번에는 파일 다루기 2에서 저장했던 파일의 실제 저장 위치를 가져오도록 해보겠습니다.

 

1. external storage 권한 받아오기

private val PERMISSIONS_STORAGE = arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)

private fun saveJsonFileToExternalStorage() {
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
        
        ....
        
    } else {
        ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE)
    }
}


// -> 권한 요청을 거절했을 때를 위한 예외처리
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    when (requestCode) {
        REQUEST_EXTERNAL_STORAGE -> {
            if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !this.shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE)) {
                    AlertDialog.Builder(this)
                            .setMessage("저장하려면 권한이 필요")
                            .setCancelable(false)
                            .setPositiveButton(R.string.settings
                            ) { _, _ ->
                                try {
                                    val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                                            .setData(Uri.parse("package:$packageName"))
                                    startActivityForResult(intent, REQUEST_EXTERNAL_STORAGE)
                                } catch (e: ActivityNotFoundException) {
                                    e.printStackTrace()

                                    val intent = Intent(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS)
                                    startActivityForResult(intent, REQUEST_EXTERNAL_STORAGE)
                                }
                            }
                            .setNegativeButton(R.string.cancel
                            ) { _, _ -> }
                            .show()
                }
            }
        }
    }
}

MediaStore를 이용하여 외부 저장소에 접근해야하기 때문에 권한이 없는 상태로 query를 사용하면 퍼미션 에러에 의해 앱이 종료됩니다. 반드시 퍼미션 체크를 확실히 하고 다음으로 넘어가길 바랍니다.

 

2. MediaStore를 이용하여 real path 구하기

private val projection = arrayOf(MediaStore.Files.FileColumns._ID, MediaStore.Files.FileColumns.DISPLAY_NAME, MediaStore.Files.FileColumns.DATA, MediaStore.Files.FileColumns.BUCKET_DISPLAY_NAME)
//id와 display name, path, bucket을 가져오도록

private fun getRealPathFromURI(){
    val selection = MediaStore.Files.FileColumns.DISPLAY_NAME + " LIKE ?"
    val selectionArgs = arrayOf("%" + ".timetable")
    //DISPLAY_NAME에서 .timetable이 포함되어 있는 파일만 가져오도록
    
    val cursor: Cursor? = contentResolver.query(MediaStore.Files.getContentUri("external"), projection, selection, selectionArgs, MediaStore.Images.Media.DATE_ADDED)
    //MediaStore.Images.Media.DATE_ADDED을 이용하여 저장된 순서대로 정렬
    val dialog = AlertDialog.Builder(this)
    if (cursor != null) {
    	//가장 최신에 저장된 파일을 가져오기 위해서 마지막 파일을 읽어옴
        if (cursor.moveToLast()) {
            val path = cursor.getString(cursor.getColumnIndex(projection[2]))
            dialog.setMessage(if (path.isNullOrEmpty()) "good to save" else path)
        }
        cursor.close()
    } else {
        dialog.setMessage("good to save")
    }
    dialog.setPositiveButton(R.string.action_ok) { _, _ -> }.show()
}

MediaStore는 안드로이드 시스템에서 제공하는 미디어 데이터 DB입니다.
query를 사용하여 특정 DB만 가져올 수 있기 때문에 다양한 방법을 사용하여 자신이 원하는 결과를 얻을 수 있습니다.

 

http://dktfrmaster.blogspot.com/2016/10/mediastore.html

 

[안드로이드] MediaStore에서 파일 다루기

현업 개발자로써 삽질하는 과정을 기록하는 블로그입니다.

dktfrmaster.blogspot.com

또한 이 블로그의 글을 통하여 많은 도움을 얻었습니다.

반응형
Comments