Android文件存储 #
一、存储概述 #
Android提供了多种数据存储方式,文件存储是其中最基本的一种。根据存储位置,可以分为内部存储和外部存储。
1.1 存储分类 #
| 类型 | 说明 | 特点 |
|---|---|---|
| 内部存储 | 应用私有目录 | 不需要权限,卸载时删除 |
| 外部存储 | 共享存储目录 | 需要权限,卸载可能保留 |
| 应用专属外部存储 | 外部存储中的应用私有目录 | 不需要权限,卸载时删除 |
1.2 存储路径 #
text
内部存储:
/data/data/<package_name>/files/
/data/data/<package_name>/cache/
外部存储:
/storage/emulated/0/
应用专属外部存储:
/storage/emulated/0/Android/data/<package_name>/files/
/storage/emulated/0/Android/data/<package_name>/cache/
二、内部存储 #
内部存储是应用私有的存储空间,其他应用无法访问,不需要权限。
2.1 写入文件 #
kotlin
fun writeToFile(fileName: String, content: String) {
try {
val file = File(filesDir, fileName)
file.writeText(content)
} catch (e: IOException) {
e.printStackTrace()
}
}
// 或使用openFileOutput
fun writeToFile2(fileName: String, content: String) {
try {
openFileOutput(fileName, Context.MODE_PRIVATE).use { output ->
output.write(content.toByteArray())
}
} catch (e: IOException) {
e.printStackTrace()
}
}
2.2 读取文件 #
kotlin
fun readFromFile(fileName: String): String {
return try {
val file = File(filesDir, fileName)
file.readText()
} catch (e: IOException) {
e.printStackTrace()
""
}
}
// 或使用openFileInput
fun readFromFile2(fileName: String): String {
return try {
openFileInput(fileName).use { input ->
input.bufferedReader().readText()
}
} catch (e: IOException) {
e.printStackTrace()
""
}
}
2.3 缓存文件 #
kotlin
// 写入缓存
fun writeToCache(fileName: String, content: String) {
try {
val file = File(cacheDir, fileName)
file.writeText(content)
} catch (e: IOException) {
e.printStackTrace()
}
}
// 读取缓存
fun readFromCache(fileName: String): String {
return try {
val file = File(cacheDir, fileName)
file.readText()
} catch (e: IOException) {
e.printStackTrace()
""
}
}
// 清除缓存
fun clearCache() {
cacheDir.deleteRecursively()
}
2.4 文件操作 #
kotlin
// 获取文件列表
val files = fileList()
// 删除文件
deleteFile(fileName)
// 检查文件是否存在
val exists = File(filesDir, fileName).exists()
// 获取文件大小
val size = File(filesDir, fileName).length()
三、外部存储 #
3.1 存储权限 #
xml
<!-- 读取外部存储 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 写入外部存储(Android 10以下) -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Android 11+ 管理所有文件 -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
3.2 检查存储状态 #
kotlin
fun isExternalStorageWritable(): Boolean {
return Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED
}
fun isExternalStorageReadable(): Boolean {
val state = Environment.getExternalStorageState()
return state == Environment.MEDIA_MOUNTED || state == Environment.MEDIA_MOUNTED_READ_ONLY
}
3.3 应用专属外部存储 #
不需要权限,卸载应用时自动删除。
kotlin
// 获取外部文件目录
val externalFilesDir = getExternalFilesDir(null) // /Android/data/<package>/files/
val externalCacheDir = externalCacheDir // /Android/data/<package>/cache/
// 获取特定类型目录
val picturesDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
val downloadsDir = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
val documentsDir = getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)
val musicDir = getExternalFilesDir(Environment.DIRECTORY_MUSIC)
val moviesDir = getExternalFilesDir(Environment.DIRECTORY_MOVIES)
// 写入文件
fun writeToExternalFile(fileName: String, content: String) {
if (!isExternalStorageWritable()) return
val file = File(getExternalFilesDir(null), fileName)
file.writeText(content)
}
// 读取文件
fun readFromExternalFile(fileName: String): String {
if (!isExternalStorageReadable()) return ""
val file = File(getExternalFilesDir(null), fileName)
return file.readText()
}
3.4 公共外部存储 #
需要权限,卸载应用后文件保留。
kotlin
// Android 10及以上使用MediaStore
fun saveImageToGallery(context: Context, bitmap: Bitmap) {
val contentValues = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, "image_${System.currentTimeMillis()}.jpg")
put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES)
}
val uri = context.contentResolver.insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues
)
uri?.let {
context.contentResolver.openOutputStream(it).use { output ->
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, output)
}
}
}
// Android 9及以下
fun saveImageToGalleryLegacy(context: Context, bitmap: Bitmap) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
val picturesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
val file = File(picturesDir, "image_${System.currentTimeMillis()}.jpg")
file.outputStream().use { output ->
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, output)
}
// 通知媒体库更新
MediaScannerConnection.scanFile(
context,
arrayOf(file.absolutePath),
arrayOf("image/jpeg"),
null
)
}
}
四、动态权限请求 #
4.1 检查和请求权限 #
kotlin
private val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
// 权限已授予
saveFile()
} else {
// 权限被拒绝
Toast.makeText(this, "需要存储权限", Toast.LENGTH_SHORT).show()
}
}
fun checkAndRequestPermission() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.WRITE_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED
) {
saveFile()
} else {
requestPermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
} else {
// Android 10+ 不需要WRITE_EXTERNAL_STORAGE权限
saveFile()
}
}
4.2 Android 11+ 管理所有文件 #
kotlin
fun checkManageExternalStoragePermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (!Environment.isExternalStorageManager()) {
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
intent.data = Uri.parse("package:$packageName")
startActivity(intent)
}
}
}
五、文件选择器 #
5.1 使用Storage Access Framework #
kotlin
private val openDocumentLauncher = registerForActivityResult(
ActivityResultContracts.OpenDocument()
) { uri ->
uri?.let {
readFileFromUri(it)
}
}
fun openFile() {
openDocumentLauncher.launch(arrayOf("text/*", "application/pdf"))
}
private val createDocumentLauncher = registerForActivityResult(
ActivityResultContracts.CreateDocument("text/plain")
) { uri ->
uri?.let {
writeToFile(it, "Hello World")
}
}
fun createFile() {
createDocumentLauncher.launch("new_file.txt")
}
5.2 读取选择的文件 #
kotlin
fun readFileFromUri(uri: Uri): String {
return contentResolver.openInputStream(uri)?.use { input ->
input.bufferedReader().readText()
} ?: ""
}
fun writeToFile(uri: Uri, content: String) {
contentResolver.openOutputStream(uri)?.use { output ->
output.write(content.toByteArray())
}
}
六、文件复制与移动 #
kotlin
fun copyFile(source: File, dest: File) {
source.inputStream().use { input ->
dest.outputStream().use { output ->
input.copyTo(output)
}
}
}
fun moveFile(source: File, dest: File): Boolean {
return if (source.renameTo(dest)) {
true
} else {
copyFile(source, dest)
source.delete()
}
}
七、最佳实践 #
7.1 使用协程处理文件操作 #
kotlin
suspend fun readFileAsync(fileName: String): String = withContext(Dispatchers.IO) {
val file = File(filesDir, fileName)
file.readText()
}
suspend fun writeFileAsync(fileName: String, content: String) = withContext(Dispatchers.IO) {
val file = File(filesDir, fileName)
file.writeText(content)
}
7.2 使用FileProvider分享文件 #
xml
<!-- AndroidManifest.xml -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
xml
<!-- res/xml/file_paths.xml -->
<paths>
<files-path name="files" path="." />
<cache-path name="cache" path="." />
<external-files-path name="external_files" path="." />
</paths>
kotlin
fun shareFile(file: File) {
val uri = FileProvider.getUriForFile(
this,
"${packageName}.fileprovider",
file
)
val intent = Intent(Intent.ACTION_SEND).apply {
type = "image/*"
putExtra(Intent.EXTRA_STREAM, uri)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
startActivity(Intent.createChooser(intent, "分享文件"))
}
7.3 定期清理缓存 #
kotlin
fun clearOldCache() {
val cacheDir = cacheDir
val currentTime = System.currentTimeMillis()
val oneWeek = 7 * 24 * 60 * 60 * 1000L
cacheDir.listFiles()?.forEach { file ->
if (currentTime - file.lastModified() > oneWeek) {
file.delete()
}
}
}
八、总结 #
本章详细介绍了Android文件存储:
- 存储分类和路径
- 内部存储的使用
- 外部存储的使用
- 动态权限请求
- 文件选择器
- 文件操作最佳实践
合理使用文件存储可以满足各种数据持久化需求,但要注意权限管理和存储空间的合理使用。
最后更新:2026-03-26