Foggy day
[Android] Android read file 본문
이번 포스팅에서는 디바이스에 있는 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
}
}
소스코드
'Android' 카테고리의 다른 글
[Android] PACKAGE_USAGE_STATS 권한 획득 (0) | 2023.09.26 |
---|---|
[Android] SYSTEM_ALERT_WINDOW 권한 획득 (0) | 2023.09.26 |
[Android] Boot App(부트앱) 만들기 (0) | 2023.08.27 |
[Android] Android launcher basic (0) | 2023.08.27 |
[Android] Debug 모드로 앱 설치시 아이콘 사라지는 현상 (0) | 2021.09.13 |