Android录音合并MP3触发java.io.FileNotFoundException问题求助
解决Android录音合并MP3时的FileNotFoundException问题
咱们一步步拆解问题,从权限、路径、逻辑顺序三个核心方向来排查修复:
1. 补全动态存储权限(Android 6.0+必做)
你只在清单文件中声明了WRITE_EXTERNAL_STORAGE权限,但Android 6.0(API 23)及以上版本,这类危险权限需要动态申请,否则系统会直接拒绝读写请求,导致文件无法创建或访问。
添加动态权限申请代码(建议在录音前执行):
private static final int REQUEST_STORAGE_PERM = 101; // 检查并申请存储权限 private void checkStoragePermission() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_STORAGE_PERM); } } // 处理权限申请结果 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_STORAGE_PERM) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 权限获取成功,执行录音/合并操作 } else { Toast.makeText(this, "需要存储权限才能录制和保存音频", Toast.LENGTH_SHORT).show(); } } }
注意:Android 10及以上可在<application>标签添加android:requestLegacyExternalStorage="true",暂时兼容旧存储逻辑,避免分区存储限制影响。
2. 修复目录创建与路径拼接问题
(1)用mkdirs()替代mkdir()
你当前用f.mkdir()创建目录,如果父目录(比如R.string.PATH对应的目录)不存在,mkdir()会创建失败。换成mkdirs()可以递归创建所有缺失的父目录:
File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + Global.gContext.getResources().getString(R.string.PATH) + File.separator + "Luyin"); if(!f.exists()){ f.mkdirs(); // 递归创建所有父目录 }
(2)规范路径拼接方式
voiceName的初始化建议用File的getAbsolutePath()方法,避免直接拼接File对象导致的格式异常:
String voiceName = f.getAbsolutePath() + File.separator;
(3)提前创建临时文件目录
录音临时文件的temp目录需要提前创建,否则MP3Recorder无法在不存在的目录下创建文件:
// 创建temp目录 File tempDir = new File(voiceName + "temp"); if (!tempDir.exists()) { tempDir.mkdirs(); } // 生成临时录音文件 File tempAudioFile = new File(tempDir, sound + soundNum + ".mp3"); mRecorder = new MP3Recorder(tempAudioFile);
3. 调整合并逻辑的顺序与文件检查
(1)修正stop()方法的执行顺序
你当前先合并再检查文件是否存在,逻辑颠倒。应该先检查是否有可合并的录音片段,再执行合并,最后验证结果:
private void stop() { mRecorder.stop(); // 先检查是否有录制的片段 if (soundList.isEmpty()) { Global.show("请先录制声音"); return; } alertDialog.setMessage("正在合成,请稍后……"); alertDialog.show(); // 执行合并 heBingMp3(); // 检查合并后的文件 File mergedFile = new File(voiceName + sound + ".mp3"); if (mergedFile.exists()) { wancheng = true; new DecodeAudioTask(mergedFile.getAbsolutePath()).execute(); } else { Global.show("音频合成失败"); alertDialog.dismiss(); } }
(2)完善heBingMp3()的异常防护
在合并时增加临时文件存在性检查,避免读取不存在的文件触发异常:
public void heBingMp3(){ File mergedFile = new File(voiceName + sound + ".mp3"); // 确保目标文件父目录存在 if (!mergedFile.getParentFile().exists()) { mergedFile.getParentFile().mkdirs(); } try (FileOutputStream out = new FileOutputStream(mergedFile, true)) { for(String tempPath : soundList){ File tempFile = new File(tempPath); // 跳过不存在的临时文件 if (!tempFile.exists()) continue; try (FileInputStream in = new FileInputStream(tempFile)) { byte[] bs = new byte[1024*4]; int len; while((len=in.read(bs))!=-1){ out.write(bs,0,len); } tempFile.delete(); } } }catch (Exception e){ e.printStackTrace(); Global.show("合并音频时出错"); } }
(3)规范soundList的添加逻辑
添加临时文件路径时,直接用tempAudioFile.getAbsolutePath(),避免手动拼接导致的路径错误:
// 录音完成后添加到列表 soundList.add(tempAudioFile.getAbsolutePath());
按照上面的步骤逐一调整,应该就能解决文件找不到的问题了。
内容的提问来源于stack exchange,提问作者Jcy.D.Shanks
相关产品推荐
相关产品推荐

