安卓文件写入异常:文件存在却触发FileNotFoundException
日志信息
D/sticky note: /storage/emulated/0/Pictures/PlantImages/20230325_151658.jpg文件已存在!
W/System.err: java.io.FileNotFoundException: /storage/emulated/0/Pictures/PlantImages/20230325_151658.jpg
出错的写入代码
Uri uri = AddActivity.uri1; String path = getFile(uri); File file = new File(path); file.setWritable(true); //MeViewHolder //MeViewHolder if (!file.exists()) { System.out.println("file does not exist"); return; } // 打开可写通道 try (FileOutputStream outputStream = new FileOutputStream(file)) { // 写入数据 byte[] data = "Hello, World!".getBytes(); outputStream.write(data); System.out.println("write success"); } catch (IOException e) { e.printStackTrace(); }
已确认的情况
- 文件实际存在,路径完全正确,已获取读写权限
- 该图片文件可通过OpenCV正常处理
- 图片上传相关代码片段:
Bitmap img = (Bitmap) data.getExtras().get("data"); imgCamera.setImageBitmap(img);
图片保存到MediaStore的代码
// 将图片保存至设备MediaStore String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); File folder = new File(Environment.getExternalStorageDirectory(), FOLDER_NAME); if (!folder.exists()) { folder.mkdirs(); } String fileName = timeStamp + ".jpg"; ContentValues values = new ContentValues(); values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName); values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg"); values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/" + FOLDER_NAME); Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); try { OutputStream outputStream = getContentResolver().openOutputStream(uri); if (outputStream != null) { // 压缩图片并保存至输出流 img.compress(Bitmap.CompressFormat.JPEG, 90, outputStream); outputStream.close(); Toast.makeText(this, "图片保存成功", Toast.LENGTH_SHORT).show(); AddActivity.uri1 = uri; } } catch (IOException e) { e.printStackTrace(); }
可能的异常原因及排查点
Android 10+分区存储限制
从Android 10开始启用分区存储,直接通过FileAPI访问外部媒体文件会有权限限制。你保存图片时用MediaStore获取Uri,但写入时转成File路径操作,这是核心冲突。应该直接用ContentResolver.openOutputStream(uri)写入,而非FileOutputStream。权限未正确生效
Android 13+针对媒体文件新增READ_MEDIA_IMAGES/WRITE_MEDIA_IMAGES权限,若targetSdkVersion >=33,需申请这些权限而非旧的WRITE_EXTERNAL_STORAGE。可通过Context.checkSelfPermission()再次验证权限状态。Uri转路径错误
getFile(uri)方法可能返回无效路径,比如MediaStore的Uri对应的真实物理路径和你拿到的不一致,或者该路径只是媒体库的映射,并非可直接写入的路径。文件被占用
图片若被其他应用或系统进程占用(如图库加载),会导致无法写入。可重启设备测试,或确认无其他进程在使用该文件。
内容的提问来源于stack exchange,提问作者Zhu Pengming

