fix(android): 增强备份导出验证 - 添加 0 字节检查和显式流创建检查 [CRITICAL]
【数据完整性加固 - 三层防护】
## 问题背景
虽然前一版本已添加完整性验证,但存在两个可能导致误报成功的边缘情况:1. 流创建失败但未明确检测
2. 文件写入 0 字节但未专门检查
## 修复内容
### 1. 显式流创建检查```kotlin// 修复前(Elvis 运算符隐式检查,可读性差)
context.contentResolver.openOutputStream(uri)?.use { ... } ?: throw Exception(...)
// 修复后(显式检查,逻辑清晰)
val outputStream = context.contentResolver.openOutputStream(uri)
?: throw Exception("无法创建输出流 - 可能是权限问题或存储已满")
outputStream.use { ... }
```
### 2. 三层验证机制
```kotlin
// 第1层:检查文件是否为空(0字节)
if (writtenContent.isEmpty()) {
throw Exception("文件为空 (0 字节) - 写入失败")
}
// 第2层:检查长度是否匹配
if (writtenContent.length != json.length) {
throw Exception("文件长度不匹配: 期望 ${json.length}, 实际 ${writtenContent.length}")
}
// 第3层:检查内容是否完全一致if (writtenContent != json) {
throw Exception("文件内容校验失败 - 数据损坏")
}
```
## 防护场景
| 场景 | 检测方式 | 用户反馈 |
|------|----------|----------|
| **流创建失败** | Elvis 抛异常 | "无法创建输出流" |
| **0 字节写入** | isEmpty() 检查 | "文件为空 (0 字节)" |
| **部分写入** | 长度比对 | "文件长度不匹配" |
| **数据损坏** | 内容比对 | "文件内容校验失败" |
## 原子性保证
```
✅ 成功路径:写入完整 → 验证通过 → "备份文件已保存并验证成功"
❌ 失败路径:任何异常 → 删除文件 → "保存失败: [具体原因]"
```
## 验证
编译成功:✅ BUILD SUCCESSFUL in 21s
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
2d0692a96f
commit
c37c85838b
|
|
@ -159,25 +159,42 @@ fun TssPartyApp(
|
|||
val expectedLength = jsonBytes.size
|
||||
android.util.Log.d("MainActivity", "[EXPORT-FILE] Writing $expectedLength bytes...")
|
||||
|
||||
// 写入文件
|
||||
context.contentResolver.openOutputStream(targetUri)?.use { outputStream ->
|
||||
outputStream.write(jsonBytes)
|
||||
outputStream.flush() // 确保数据真正写入存储
|
||||
android.util.Log.d("MainActivity", "[EXPORT-FILE] Write and flush completed")
|
||||
} ?: throw Exception("无法创建输出流")
|
||||
// 写入文件(显式检查流创建)
|
||||
val outputStream = context.contentResolver.openOutputStream(targetUri)
|
||||
?: throw Exception("无法创建输出流 - 可能是权限问题或存储已满")
|
||||
|
||||
// 验证写入完整性
|
||||
outputStream.use {
|
||||
it.write(jsonBytes)
|
||||
it.flush() // 确保数据真正写入存储
|
||||
android.util.Log.d("MainActivity", "[EXPORT-FILE] Write and flush completed")
|
||||
}
|
||||
|
||||
// 验证写入完整性(显式检查流创建)
|
||||
android.util.Log.d("MainActivity", "[EXPORT-FILE] Verifying file integrity...")
|
||||
context.contentResolver.openInputStream(targetUri)?.use { inputStream ->
|
||||
val writtenContent = inputStream.bufferedReader().readText()
|
||||
val inputStream = context.contentResolver.openInputStream(targetUri)
|
||||
?: throw Exception("无法读取已写入的文件 - 文件可能未创建")
|
||||
|
||||
inputStream.use {
|
||||
val writtenContent = it.bufferedReader().readText()
|
||||
android.util.Log.d("MainActivity", "[EXPORT-FILE] Read back ${writtenContent.length} bytes")
|
||||
|
||||
// 首先检查文件是否为空(0字节)
|
||||
if (writtenContent.isEmpty()) {
|
||||
throw Exception("文件为空 (0 字节) - 写入失败")
|
||||
}
|
||||
|
||||
// 检查长度是否匹配
|
||||
if (writtenContent.length != json.length) {
|
||||
throw Exception("文件长度不匹配: 期望 ${json.length}, 实际 ${writtenContent.length}")
|
||||
}
|
||||
|
||||
// 检查内容是否完全一致
|
||||
if (writtenContent != json) {
|
||||
throw Exception("文件内容校验失败")
|
||||
throw Exception("文件内容校验失败 - 数据损坏")
|
||||
}
|
||||
android.util.Log.d("MainActivity", "[EXPORT-FILE] Integrity verification passed")
|
||||
} ?: throw Exception("无法读取已写入的文件进行验证")
|
||||
|
||||
android.util.Log.d("MainActivity", "[EXPORT-FILE] Integrity verification passed: ${writtenContent.length} bytes, content matches")
|
||||
}
|
||||
|
||||
// 验证通过
|
||||
writeSucceeded = true
|
||||
|
|
|
|||
Loading…
Reference in New Issue