上一篇
安卓往存储写文件工作流程
- 行业动态
- 2025-05-03
- 1
安卓写入存储流程:申请权限→获取存储路径→创建文件输出流→写入数据→关闭流,需处理运行时权限及Android
安卓往存储写文件工作流程
权限检查
- Android 9及以下:需在
AndroidManifest.xml
中声明WRITE_EXTERNAL_STORAGE
权限,并在运行时动态申请(Android 6.0+)。 - Android 10+:引入“分区存储”(Scoped Storage),外部存储分为“应用私有目录”和“公共目录”。
- 写入应用私有目录(如
getExternalFilesDir()
)无需额外权限。 - 写入公共目录(如
Environment.getExternalStoragePublicDirectory()
)需通过Storage Access Framework
或MediaStore
API。
- 写入应用私有目录(如
确定存储位置
存储类型 | 路径示例 | 适用场景 |
---|---|---|
内部存储 | /data/data/包名/files/ | 应用私有数据,无需申请权限 |
外部存储(私有) | /storage/emulated/0/Android/data/包名/ | Android 10+自动分配,无需权限 |
外部存储(公共) | /storage/emulated/0/Download/ | 需用户授权或SAF,Android 10+受限 |
缓存目录 | /data/data/包名/cache/ | 临时文件,可被系统清理 |
创建文件或目录
// 示例:在外部存储私有目录创建文件 File dir = new File(context.getExternalFilesDir(null), "MyApp"); if (!dir.exists()) { dir.mkdirs(); // 递归创建目录 } File file = new File(dir, "data.txt");
- 注意事项:
- 文件名需合法,避免特殊字符(如、
)。
- 通过
file.exists()
检查是否已存在,避免覆盖。
- 文件名需合法,避免特殊字符(如、
写入数据
try (FileOutputStream fos = new FileOutputStream(file)) { String data = "Hello World"; fos.write(data.getBytes()); // 写入字节数组 fos.flush(); // 确保数据写入磁盘 } catch (IOException e) { e.printStackTrace(); }
- 优化建议:
- 大文件可使用
BufferedOutputStream
提高写入效率。 - 二进制文件需按特定格式编码(如图片、音频)。
- 大文件可使用
异常处理与资源释放
- 常见异常:
FileNotFoundException
:路径不存在或无权限。IOException
:存储空间不足或SD卡被移除。
- 资源释放:
- 使用
try-with-resources
自动关闭流,避免内存泄漏。 - Android 10+需处理
ScopedAccessFailedException
(公共目录访问失败)。
- 使用
兼容性处理(Android 10+)
- 替代方案:
- Storage Access Framework:通过
Intent.ACTION_CREATE_DOCUMENT
让用户选择保存位置。 - MediaStore API:写入媒体文件(图片、视频)到公共目录。
- Storage Access Framework:通过
- 示例:
// 使用MediaStore保存图片 ContentValues values = new ContentValues(); values.put(MediaStore.Images.Media.DISPLAY_NAME, "photo.jpg"); values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg"); Uri uri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); try (OutputStream os = context.getContentResolver().openOutputStream(uri)) { // 写入图片数据 }
相关问题与解答
问题1:如何在Android 10+中兼容写入外部存储?
解答:
- 应用私有目录:直接使用
getExternalFilesDir()
,无需权限。 - 公共目录:
- 使用
Storage Access Framework
(SAF)让用户选择目录。 - 通过
MediaStore
API写入媒体文件。 - 避免直接使用
Environment.getExternalStoragePublicDirectory()
,会导致ScopedAccessFailedException
。
- 使用
问题2:写入大文件时如何避免内存溢出(OOM)?
解答:
- 分块写入:将大文件拆分为小块,逐块写入磁盘。
- 使用缓冲流:例如
BufferedOutputStream
减少I/O次数。 - 异步处理:在子线程中执行写入操作,避免阻塞主线程。
- 示例代码:
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file))) { byte[] buffer = new byte[8192]; // 8KB缓冲区 int len; while ((len = inputStream.read(buffer)) != -1) { bos.write(buffer, 0, len); } } catch (IOException e) { e.printStackTrace(); }