Android
[Android] Android read file
jinhan38
2023. 8. 30. 01:19
이번 포스팅에서는 디바이스에 있는 file들을 불러오는 것을 해보겠습니다.
1. 권한처리
2. ReadDeviceFile
1. 권한처리
Android api level 29를 기점으로 권한 처리를 다르게 해야합니다.
만약에 29 이하라고 한다면 READ_EXTERNAL_STORAGE권한을 추가 해야하고 런타임 권한을 획득해야 합니다.
30 이상이라면 MANAGE_EXTERNAL_STORAGE 권한을 추가하고, 모든 파일에 대한 접근 권한을 허용할 수 있는 시스템 창을 호출해야 합니다. 또한 외부 폴더에 접근하기 위해서는 Manifest의 appliction 태그 안에 android:requestLegacyExternalStorage="true"를 추가해야 합니다.
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!--모든 파일에 대한 접근 권한 api level 30이상부터 필요-->
<uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Android_storage_file_read"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
</application>
</manifest>
MainActivity
package com.example.android_storage_file_read
import android.Manifest.permission.READ_EXTERNAL_STORAGE
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.provider.Settings
import android.util.Log
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
class MainActivity : AppCompatActivity() {
companion object {
private const val TAG = "MainActivity Log"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.d(TAG, "onCreate: Build.VERSION.SDK_INT : ${Build.VERSION.SDK_INT}")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (!Environment.isExternalStorageManager()) {
val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
startActivity(intent)
}
} else {
checkStoragePermissions()
}
findViewById<Button>(R.id.button).setOnClickListener {
try {
ReadDeviceFile.apply {
val files = getFiles("/sdcard/Download")
Log.d(TAG, "onCreate: files : $files")
val file = getFileOne("/sdcard/Download", "readFile")
val result = readTextFile(file)
Log.d(TAG, "onCreate: result : $result")
}
} catch (e: Exception) {
Log.e(TAG, "read error", e)
}
}
}
private fun checkStoragePermissions() {
try {
val permission = ContextCompat.checkSelfPermission(
this,
READ_EXTERNAL_STORAGE
)
if (permission == PackageManager.PERMISSION_DENIED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(
arrayOf(READ_EXTERNAL_STORAGE),
1000
)
}
return
}
} catch (e: Exception) {
Log.d(TAG, "checkStoragePermissions error : $e")
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String?>, grandResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grandResults)
if (requestCode == 1000) {
var checkResult = true
for (result in grandResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
checkResult = false
break
}
}
}
}
}
2. ReadDeviceFile
ReadDeviceFile obejct에는 3개의 함수가 있습니다.
- getFile : 경로를 입력하면 해당 경로에 있는 모든 파일과 폴더들을 불러올 수 있습니다.
- getFiles : 경로와 file이름을 입력하면 해당 파일을 리턴합니다.
- readTextFile : txt파일을 전달하면 내용을 읽을 수 있습니다.
import java.io.BufferedReader
import java.io.File
import java.io.FileReader
object ReadDeviceFile {
/**
* Loads files in a specific path.
*/
fun getFiles(path: String): ArrayList<File> {
val files = File(path).listFiles()
if (files.isNullOrEmpty()) return arrayListOf()
return files.toCollection(ArrayList())
}
/**
* Loads a file in a specific path.
*/
fun getFileOne(path: String, fileName: String): File {
val files = File(path).listFiles()
if (files.isNullOrEmpty()) throw Exception("The files do not exist in the $path")
var filePath = ""
for (f in files) {
if (f.name.contains(fileName)) {
filePath = f.path
break
}
}
if (filePath.isEmpty()) throw Exception("$fileName does not exist in $path.")
val file = File(filePath)
if (!file.exists()) throw Exception("File is not exists")
return file
}
/**
* Read the contents of a text file
*/
fun readTextFile(file: File): StringBuilder {
val fileType = file.name.toString().substring(file.name.length - 3, file.name.length)
if (fileType != "txt") {
throw Exception("${file.name} is not a text file")
}
val reader = BufferedReader(FileReader(file))
val textBuilder = StringBuilder()
var line: String?
while (reader.readLine().also { line = it } != null) {
textBuilder.append(line)
textBuilder.append("\n")
}
return textBuilder
}
}
소스코드